diff options
20 files changed, 5196 insertions, 5242 deletions
diff --git a/integrity-audit/src/main/java/org/onap/policy/common/ia/AuditThread.java b/integrity-audit/src/main/java/org/onap/policy/common/ia/AuditThread.java index efa1b1d3..f1839b12 100644 --- a/integrity-audit/src/main/java/org/onap/policy/common/ia/AuditThread.java +++ b/integrity-audit/src/main/java/org/onap/policy/common/ia/AuditThread.java @@ -35,869 +35,794 @@ import org.onap.policy.common.logging.flexlogger.FlexLogger; import org.onap.policy.common.logging.flexlogger.Logger; /** - * AuditThread is the main thread for the IntegrityAudit + * AuditThread is the main thread for the IntegrityAudit. * */ public class AuditThread extends Thread { - private static final Logger logger = FlexLogger.getLogger(AuditThread.class); - - /* - * Number of milliseconds that must elapse for audit to be considered - * complete. It's public for access by JUnit test logic. - */ - public static final long AUDIT_COMPLETION_INTERVAL = 30000; - - /* - * Number of iterations for audit simulation. - */ - public static final long AUDIT_SIMULATION_ITERATIONS = 3; - - /* - * Number of milliseconds to sleep between audit simulation iterations. It's - * public for access by JUnit test logic. - */ - public static final long AUDIT_SIMULATION_SLEEP_INTERVAL = 5000; - - /* - * Unless audit has already been run on this entity, number of milliseconds - * to sleep between audit thread iterations. If audit has already been run, - * we sleep integrityAuditPeriodMillis. May be modified by JUnit tests. - */ - private static long auditThreadSleepIntervalMillis = 5000; - - /* - * Number of milliseconds that must elapse for audit to be considered - * complete. May be modified by JUnit tests. - */ - private static long auditCompletionIntervalMillis = AUDIT_COMPLETION_INTERVAL; - - /* - * DB access class. - */ - private DbDAO dbDAO; - - /* - * E.g. pdp_xacml - */ - private String nodeType; - - /* - * Persistence unit for which this audit is being run. - */ - private String persistenceUnit; - - /* - * Name of this resource - */ - private String resourceName; - - /* - * E.g. DB_DRIVER, SITE_NAME, NODE_TYPE - */ - private Properties properties; - - /* - * See IntegrityAudit class for usage. - */ - private long integrityAuditPeriodMillis; - - /* - * The containing IntegrityAudit instance - */ - private IntegrityAudit integrityAudit; - - /** - * A latch is taken from this queue before starting an audit. May be - * {@code null}. Used by JUnit tests. - */ - private BlockingQueue<CountDownLatch> auditLatchQueue; - - /** - * Latch to be decremented when the next audit completes. May be - * {@code null}. Used by JUnit tests to wait for an audit to complete. - */ - private CountDownLatch auditCompletionLatch = null; - - /** - * AuditThread constructor - * @param resourceName - * @param persistenceUnit - * @param properties - * @param integrityAuditPeriodSeconds - * @param integrityAudit - * @throws IntegrityAuditException - */ - public AuditThread(String resourceName, String persistenceUnit, - Properties properties, int integrityAuditPeriodSeconds, IntegrityAudit integrityAudit) - throws IntegrityAuditException { - - this(resourceName, persistenceUnit, properties, TimeUnit.SECONDS.toMillis(integrityAuditPeriodSeconds), - integrityAudit, null); - } - - /** - * AuditThread constructor - * @param resourceName - * @param persistenceUnit - * @param properties - * @param integrityAuditMillis - * @param integrityAudit - * @param queue - * @throws IntegrityAuditException - */ - public AuditThread(String resourceName, String persistenceUnit, - Properties properties, long integrityAuditMillis, IntegrityAudit integrityAudit, - BlockingQueue<CountDownLatch> queue) - throws IntegrityAuditException { - this.resourceName = resourceName; - this.persistenceUnit = persistenceUnit; - this.properties = properties; - this.integrityAuditPeriodMillis = integrityAuditMillis; - this.integrityAudit = integrityAudit; - this.auditLatchQueue = queue; - - /* - * The DbDAO Constructor registers this node in the IntegrityAuditEntity - * table. Each resource (node) inserts its own name, persistenceUnit, DB - * access properties and other pertinent properties in the table. This - * allows the audit on each node to compare its own version of the - * entities for the persistenceUnit in question with the versions from - * all other nodes of similar type. - */ - dbDAO = new DbDAO(this.resourceName, this.persistenceUnit, - this.properties); - this.nodeType = properties.getProperty(IntegrityAuditProperties.NODE_TYPE); - - } - - @Override - public void run() { - - logger.info("AuditThread.run: Entering"); - - try { - /* - * For JUnit testing: wait for the first latch, decrement it to - * indicate that the thread has started, and then wait for the - * next latch, before we actually start doing anything. These - * simply return if there is no latch queue defined. - */ - getNextLatch(); - decrementLatch(); - getNextLatch(); - - /* - * Triggers change in designation, unless no other viable candidate. - */ - boolean auditCompleted = false; - - DbAudit dbAudit = new DbAudit(dbDAO); - - IntegrityAuditEntity entityCurrentlyDesignated; - IntegrityAuditEntity thisEntity; - integrityAudit.setThreadInitialized(true); // An exception will set - // it to false - - while (true) { - try{ - /* - * It may have been awhile since we last cycled through this - * loop, so refresh the list of IntegrityAuditEntities. - */ - List<IntegrityAuditEntity> integrityAuditEntityList = getIntegrityAuditEntityList(); - - /* - * We could've set entityCurrentlyDesignated as a side effect of - * getIntegrityAuditEntityList(), but then we would've had to - * make entityCurrentlyDesignated a class level attribute. Using - * this approach, we can keep it local to the run() method. - */ - entityCurrentlyDesignated = getEntityCurrentlyDesignated(integrityAuditEntityList); - - /* - * Need to refresh thisEntity each time through loop, because we - * need a fresh version of lastUpdated. - */ - thisEntity = getThisEntity(integrityAuditEntityList); - - /* - * If we haven't done the audit yet, note that we're current and - * see if we're designated. - */ - if (!auditCompleted) { - dbDAO.setLastUpdated(); - - /* - * If no current designation or currently designated node is - * stale, see if we're the next node to be designated. - */ - if (entityCurrentlyDesignated == null - || isStale(entityCurrentlyDesignated)) { - IntegrityAuditEntity designationCandidate = getDesignationCandidate(integrityAuditEntityList); - - /* - * If we're the next node to be designated, run the - * audit. - */ - if (designationCandidate.getResourceName().equals( - this.resourceName)) { - runAudit(dbAudit); - auditCompleted = true; - } else { - if (logger.isDebugEnabled()) { - logger.debug("AuditThread.run: designationCandidate, " - + designationCandidate - .getResourceName() - + ", not this entity, " - + thisEntity.getResourceName()); - } - } - - /* - * Application may have been stopped and restarted, in - * which case we might be designated but auditCompleted - * will have been reset to false, so account for this. - */ - } else if (thisEntity.getResourceName().equals( - entityCurrentlyDesignated.getResourceName())) { - - if (logger.isDebugEnabled()) { - logger.debug("AuditThread.run: Re-running audit for " - + thisEntity.getResourceName()); - } - runAudit(dbAudit); - auditCompleted = true; - - } else { - if (logger.isDebugEnabled()) { - logger.debug("AuditThread.run: Currently designated node, " - + entityCurrentlyDesignated - .getResourceName() - + ", not yet stale and not this node"); - } - } - - - /* - * Audit already completed on this node, so allow the node - * to go stale until twice the AUDIT_COMPLETION_PERIOD has - * elapsed. This should give plenty of time for another node - * (if another node is out there) to pick up designation. - */ - } else { - - auditCompleted = resetAuditCompleted(auditCompleted, - thisEntity); - - } - - /* - * If we've just run audit, sleep per the - * integrity_audit_period_seconds property, otherwise just sleep - * the normal interval. - */ - if (auditCompleted) { - // indicate that an audit has completed - decrementLatch(); - - // don't start the next audit cycle until a latch has been provided - getNextLatch(); - - if (logger.isDebugEnabled()) { - logger.debug("AuditThread.run: Audit completed; resourceName=" - + this.resourceName - + " sleeping " - + integrityAuditPeriodMillis + "ms"); - } - Thread.sleep(integrityAuditPeriodMillis); - if (logger.isDebugEnabled()) { - logger.debug("AuditThread.run: resourceName=" - + this.resourceName + " awaking from " - + integrityAuditPeriodMillis + "ms sleep"); - } - - } else { - - if (logger.isDebugEnabled()) { - logger.debug("AuditThread.run: resourceName=" - + this.resourceName + ": Sleeping " - + AuditThread.auditThreadSleepIntervalMillis - + "ms"); - } - Thread.sleep(AuditThread.auditThreadSleepIntervalMillis); - if (logger.isDebugEnabled()) { - logger.debug("AuditThread.run: resourceName=" - + this.resourceName + ": Awaking from " - + AuditThread.auditThreadSleepIntervalMillis - + "ms sleep"); - } - - } - - } catch (Exception e){ - if(isInterruptedException(e)) { - String msg = "AuditThread.run loop - Exception thrown: " + e.getMessage() - + "; Stopping."; - logger.error(MessageCodes.EXCEPTION_ERROR, e, msg); - break; - } - - String msg = "AuditThread.run loop - Exception thrown: " + e.getMessage() - + "; Will try audit again in " + (integrityAuditPeriodMillis/1000) + " seconds"; - logger.error(MessageCodes.EXCEPTION_ERROR, e, msg); - // Sleep and try again later - Thread.sleep(integrityAuditPeriodMillis); - } - - } - - } catch (Exception e) { - String msg = "AuditThread.run: Could not start audit loop. Exception thrown; message="+ e.getMessage(); - logger.error(MessageCodes.EXCEPTION_ERROR, e, msg); - integrityAudit.setThreadInitialized(false); - } - - dbDAO.destroy(); - - logger.info("AuditThread.run: Exiting"); - } - - /** - * Gets the next audit-completion latch from the queue. Blocks, if the - * queue is empty. - * @throws InterruptedException - */ - private void getNextLatch() throws InterruptedException { - BlockingQueue<CountDownLatch> queue = this.auditLatchQueue; - if(queue != null) { - this.auditCompletionLatch = queue.take(); - } - } - - /** - * Decrements the current audit-completion latch, if any. - */ - private void decrementLatch() { - CountDownLatch latch = this.auditCompletionLatch; - if(latch != null) { - this.auditCompletionLatch = null; - latch.countDown(); - } - } - - /** - * Determines if an exception is an InterruptedException or was caused - * by an InterruptedException. - * @param ex exception to be examined - * @return {@code true} if it's an InterruptedException, {@code false} otherwise - */ - private boolean isInterruptedException(Throwable ex) { - while(ex != null) { - if(ex instanceof InterruptedException) { - return true; - } - - ex = ex.getCause(); - } - - return false; - } - - /* - * Used to create a list that is sorted lexicographically by resourceName. - */ - Comparator<IntegrityAuditEntity> comparator = new Comparator<IntegrityAuditEntity>() { - @Override - public int compare(final IntegrityAuditEntity r1, - final IntegrityAuditEntity r2) { - return r1.getResourceName().compareTo(r2.getResourceName()); - } - }; - - /** - * getDesignationCandidate() - * Using round robin algorithm, gets next candidate to be designated. Assumes - * list is sorted lexicographically by resourceName. - */ - private IntegrityAuditEntity getDesignationCandidate( - List<IntegrityAuditEntity> integrityAuditEntityList) { - - //Note: assumes integrityAuditEntityList is already lexicographically sorted by resourceName - - if (logger.isDebugEnabled()) { - logger.debug("getDesignationCandidate: Entering, integrityAuditEntityList.size()=" - + integrityAuditEntityList.size()); - } - - IntegrityAuditEntity designationCandidate; - IntegrityAuditEntity thisEntity = null; - - int designatedEntityIndex = -1; - int entityIndex = 0; - int priorCandidateIndex = -1; - int subsequentCandidateIndex = -1; - - for (IntegrityAuditEntity integrityAuditEntity : integrityAuditEntityList) { - - if (logger.isDebugEnabled()) { - logIntegrityAuditEntity(integrityAuditEntity); - } - - if (integrityAuditEntity.getResourceName() - .equals(this.resourceName)) { - if (logger.isDebugEnabled()) { - logger.debug("getDesignationCandidate: thisEntity=" - + integrityAuditEntity.getResourceName()); - } - thisEntity = integrityAuditEntity; - } - - if (integrityAuditEntity.isDesignated()) { - if (logger.isDebugEnabled()) { - logger.debug("getDesignationCandidate: Currently designated entity resourceName=" - + integrityAuditEntity.getResourceName() - + ", persistenceUnit=" - + integrityAuditEntity.getPersistenceUnit() - + ", lastUpdated=" - + integrityAuditEntity.getLastUpdated() - + ", entityIndex=" + entityIndex); - } - designatedEntityIndex = entityIndex; - - /* - * Entity not currently designated - */ - } else { - - /* - * See if non-designated entity is stale. - */ - if (isStale(integrityAuditEntity)) { - - if (logger.isDebugEnabled()) { - logger.debug("getDesignationCandidate: Entity is stale; resourceName=" - + integrityAuditEntity.getResourceName() - + ", persistenceUnit=" - + integrityAuditEntity.getPersistenceUnit() - + ", lastUpdated=" - + integrityAuditEntity.getLastUpdated() - + ", entityIndex=" + entityIndex); - } - - /* - * Entity is current. - */ - } else { - - if (designatedEntityIndex == -1) { - - if (priorCandidateIndex == -1) { - if (logger.isDebugEnabled()) { - logger.debug("getDesignationCandidate: Prior candidate found, resourceName=" - + integrityAuditEntity - .getResourceName() - + ", persistenceUnit=" - + integrityAuditEntity - .getPersistenceUnit() - + ", lastUpdated=" - + integrityAuditEntity.getLastUpdated() - + ", entityIndex=" + entityIndex); - } - priorCandidateIndex = entityIndex; - } else { - if (logger.isDebugEnabled()) { - logger.debug("getDesignationCandidate: Prior entity current but prior candidate already found; resourceName=" - + integrityAuditEntity - .getResourceName() - + ", persistenceUnit=" - + integrityAuditEntity - .getPersistenceUnit() - + ", lastUpdated=" - + integrityAuditEntity.getLastUpdated() - + ", entityIndex=" + entityIndex); - } - } - } else { - if (subsequentCandidateIndex == -1) { - if (logger.isDebugEnabled()) { - logger.debug("getDesignationCandidate: Subsequent candidate found, resourceName=" - + integrityAuditEntity - .getResourceName() - + ", persistenceUnit=" - + integrityAuditEntity - .getPersistenceUnit() - + ", lastUpdated=" - + integrityAuditEntity.getLastUpdated() - + ", entityIndex=" + entityIndex); - } - subsequentCandidateIndex = entityIndex; - } else { - if (logger.isDebugEnabled()) { - logger.debug("getDesignationCandidate: Subsequent entity current but subsequent candidate already found; resourceName=" - + integrityAuditEntity - .getResourceName() - + ", persistenceUnit=" - + integrityAuditEntity - .getPersistenceUnit() - + ", lastUpdated=" - + integrityAuditEntity.getLastUpdated() - + ", entityIndex=" + entityIndex); - } - } - } - - } // end entity is current - - } // end entity not currently designated - - entityIndex++; - - } // end for loop - - /* - * Per round robin algorithm, if a current entity is found that is - * lexicographically after the currently designated entity, this entity - * becomes the designation candidate. If no current entity is found that - * is lexicographically after currently designated entity, we cycle back - * to beginning of list and pick the first current entity as the - * designation candidate. - */ - if (subsequentCandidateIndex != -1) { - designationCandidate = integrityAuditEntityList - .get(subsequentCandidateIndex); - if (logger.isDebugEnabled()) { - logger.debug("getDesignationCandidate: Exiting and returning subsequent designationCandidate=" - + designationCandidate.getResourceName()); - } - } else { - if (priorCandidateIndex != -1) { - designationCandidate = integrityAuditEntityList - .get(priorCandidateIndex); - if (logger.isDebugEnabled()) { - logger.debug("getDesignationCandidate: Exiting and returning prior designationCandidate=" - + designationCandidate.getResourceName()); - } - } else { - logger.debug("getDesignationCandidate: No subsequent or prior candidate found; designating thisEntity, resourceName=" - + thisEntity.getResourceName()); - designationCandidate = thisEntity; - } - } - - return designationCandidate; - - } - - /** - * getEntityCurrentlyDesignated() - * Returns entity that is currently designated. - * @param integrityAuditEntityList - * @return - */ - private IntegrityAuditEntity getEntityCurrentlyDesignated( - List<IntegrityAuditEntity> integrityAuditEntityList) { - - if (logger.isDebugEnabled()) { - logger.debug("getEntityCurrentlyDesignated: Entering, integrityAuditEntityList.size=" - + integrityAuditEntityList.size()); - } - - IntegrityAuditEntity entityCurrentlyDesignated = null; - - for (IntegrityAuditEntity integrityAuditEntity : integrityAuditEntityList) { - - if (integrityAuditEntity.isDesignated()) { - if (logger.isDebugEnabled()) { - logger.debug("getEntityCurrentlyDesignated: Currently designated entity resourceName=" - + integrityAuditEntity.getResourceName() - + ", persistenceUnit=" - + integrityAuditEntity.getPersistenceUnit() - + ", lastUpdated=" - + integrityAuditEntity.getLastUpdated()); - } - entityCurrentlyDesignated = integrityAuditEntity; - } - - } // end for loop - - if (logger.isDebugEnabled()) { - if (entityCurrentlyDesignated != null) { - logger.debug("getEntityCurrentlyDesignated: Exiting and returning entityCurrentlyDesignated=" - + entityCurrentlyDesignated.getResourceName()); - } else { - logger.debug("getEntityCurrentlyDesignated: Exiting and returning entityCurrentlyDesignated=" - + entityCurrentlyDesignated); - } - } - return entityCurrentlyDesignated; - - } - - /** - * getIntegrityAuditEnityList gets the list of IntegrityAuditEntity - * @return - * @throws DbDaoTransactionException - */ - private List<IntegrityAuditEntity> getIntegrityAuditEntityList() - throws DbDaoTransactionException { - - if (logger.isDebugEnabled()) { - logger.debug("getIntegrityAuditEntityList: Entering"); - } - - /* - * Get all records for this nodeType and persistenceUnit and then sort - * them lexicographically by resourceName. Get index of designated - * entity, if any. - */ - /* - * Sorted list of entities for a particular nodeType and - * persistenceUnit. - */ - List<IntegrityAuditEntity> integrityAuditEntityList = dbDAO.getIntegrityAuditEntities( - this.persistenceUnit, this.nodeType); - int listSize = integrityAuditEntityList.size(); - if (logger.isDebugEnabled()) { - logger.debug("getIntegrityAuditEntityList: Got " + listSize - + " IntegrityAuditEntity records"); - } - Collections.sort((List<IntegrityAuditEntity>) integrityAuditEntityList, - comparator); - - if (logger.isDebugEnabled()) { - logger.debug("getIntegrityAuditEntityList: Exiting and returning integrityAuditEntityList, size=" - + listSize); - } - return integrityAuditEntityList; - - } - - - /** - * Returns the IntegrityAuditEntity for this entity. - * @param integrityAuditEntityList - * @return - */ - private IntegrityAuditEntity getThisEntity( - List<IntegrityAuditEntity> integrityAuditEntityList) { - - if (logger.isDebugEnabled()) { - logger.debug("getThisEntity: Entering, integrityAuditEntityList.size=" - + integrityAuditEntityList.size()); - } - - IntegrityAuditEntity thisEntity = null; - - for (IntegrityAuditEntity integrityAuditEntity : integrityAuditEntityList) { - - if (integrityAuditEntity.getResourceName().equals(this.resourceName)) { - if (logger.isDebugEnabled()) { - logger.debug("getThisEntity: For this entity, resourceName=" - + integrityAuditEntity.getResourceName() - + ", persistenceUnit=" - + integrityAuditEntity.getPersistenceUnit() - + ", lastUpdated=" - + integrityAuditEntity.getLastUpdated()); - } - thisEntity = integrityAuditEntity; - } - - } // end for loop - - if (logger.isDebugEnabled()) { - if (thisEntity != null) { - logger.debug("getThisEntity: Exiting and returning thisEntity=" - + thisEntity.getResourceName()); - } else { - logger.debug("getThisEntity: Exiting and returning thisEntity=" - + thisEntity); - } - } - return thisEntity; - - } - - - /** - * Returns false if the lastUpdated time for the record in question is more - * than auditCompletionIntervalMillis seconds ago. During an audit, lastUpdated is updated every five - * seconds or so, but when an audit finishes, the node doing the audit stops - * updating lastUpdated. - * @param integrityAuditEntity - * @return - */ - private boolean isStale(IntegrityAuditEntity integrityAuditEntity) { - - if (logger.isDebugEnabled()) { - logger.debug("isStale: Entering, resourceName=" - + integrityAuditEntity.getResourceName() - + ", persistenceUnit=" - + integrityAuditEntity.getPersistenceUnit() - + ", lastUpdated=" + integrityAuditEntity.getLastUpdated()); - } - - boolean stale = false; - - Date currentTime = new Date(); - Date lastUpdated = integrityAuditEntity.getLastUpdated(); - - /* - * If lastUpdated is null, we assume that the audit never ran for that - * node. - */ - long lastUpdatedTime = 0; - if (lastUpdated != null) { - lastUpdatedTime = lastUpdated.getTime(); - } - long timeDifference = currentTime.getTime() - lastUpdatedTime; - if (timeDifference > auditCompletionIntervalMillis) { - stale = true; - } - - if (logger.isDebugEnabled()) { - logger.debug("isStale: Exiting and returning stale=" + stale - + ", timeDifference=" + timeDifference); - } - - return stale; - } - - private void logIntegrityAuditEntity( - IntegrityAuditEntity integrityAuditEntity) { - - logger.debug("logIntegrityAuditEntity: id=" - + integrityAuditEntity.getId() + ", jdbcDriver=" - + integrityAuditEntity.getJdbcDriver() + ", jdbcPassword=" - + integrityAuditEntity.getJdbcPassword() + ", jdbcUrl=" - + integrityAuditEntity.getJdbcUrl() + ", jdbcUser=" - + integrityAuditEntity.getJdbcUser() + ", nodeType=" - + integrityAuditEntity.getNodeType() + ", persistenceUnit=" - + integrityAuditEntity.getPersistenceUnit() + ", resourceName=" - + integrityAuditEntity.getResourceName() + ", site=" - + integrityAuditEntity.getSite() + ", createdDate=" - + integrityAuditEntity.getCreatedDate() + ", lastUpdated=" - + integrityAuditEntity.getLastUpdated() + ", designated=" - + integrityAuditEntity.isDesignated()); - } - - /* - * If more than (auditCompletionIntervalMillis * 2) milliseconds have elapsed - * since we last ran the audit, reset auditCompleted, so - * - * 1) we'll eventually re-run the audit, if no other node picks up the - * designation. - * - * or - * - * 2) We'll run the audit when the round robin comes back to us. - */ - private boolean resetAuditCompleted(boolean auditCompleted, - IntegrityAuditEntity thisEntity) { - - if (logger.isDebugEnabled()) { - logger.debug("resetAuditCompleted: auditCompleted=" - + auditCompleted + "; for thisEntity, resourceName=" - + thisEntity.getResourceName() + ", persistenceUnit=" - + thisEntity.getPersistenceUnit() + ", lastUpdated=" - + thisEntity.getLastUpdated()); - } - - long timeDifference; - - Date currentTime = new Date(); - Date lastUpdated = thisEntity.getLastUpdated(); - - long lastUpdatedTime = lastUpdated.getTime(); - timeDifference = currentTime.getTime() - lastUpdatedTime; - - if (timeDifference > (auditCompletionIntervalMillis * 2)) { - if (logger.isDebugEnabled()) { - logger.debug("resetAuditCompleted: Resetting auditCompleted for resourceName=" - + this.resourceName); - } - auditCompleted = false; - } else { - if (logger.isDebugEnabled()) { - logger.debug("resetAuditCompleted: For resourceName=" - + resourceName - + ", time since last update is only " - + timeDifference + "; retaining current value for auditCompleted"); - } - } - - if (logger.isDebugEnabled()) { - logger.debug("resetAuditCompleted: Exiting and returning auditCompleted=" - + auditCompleted + ", timeDifference=" + timeDifference); - } - return auditCompleted; - } - - private void runAudit(DbAudit dbAudit) throws IntegrityAuditException { - - if (logger.isDebugEnabled()) { - logger.debug("runAudit: Entering, dbAudit=" + dbAudit - + "; notifying other resources that resourceName=" - + this.resourceName + " is current"); - } - - /* - * changeDesignated marks all other nodes as non-designated and this - * node as designated. - */ - dbDAO.changeDesignated(this.resourceName, this.persistenceUnit, - this.nodeType); - - if (logger.isDebugEnabled()) { - logger.debug("runAudit: Running audit for persistenceUnit=" - + this.persistenceUnit + " on resourceName=" - + this.resourceName); - } - if (IntegrityAudit.isUnitTesting()) { - dbAudit.dbAuditSimulate(this.resourceName, this.persistenceUnit, AuditThread.AUDIT_SIMULATION_ITERATIONS, AuditThread.auditThreadSleepIntervalMillis); - } else { - dbAudit.dbAudit(this.resourceName, this.persistenceUnit, - this.nodeType); - } - - if (logger.isDebugEnabled()) { - logger.debug("runAudit: Exiting"); - } - - } - - /** - * Adjusts the thread-sleep-interval to be used when an audit has - * <i>not</i> been completed. Used by JUnit tests. - * @param auditThreadSleepIntervalMillis - */ - protected static void setAuditThreadSleepIntervalMillis(long auditThreadSleepIntervalMillis) { - AuditThread.auditThreadSleepIntervalMillis = auditThreadSleepIntervalMillis; - } - - /** - * Gets the current thread-sleep-interval to be used when an audit has - * <i>not</i> been completed. Used by JUnit tests. - * @return the current sleep interval, in milli-seconds - */ - protected static long getAuditThreadSleepIntervalMillis() { - return auditThreadSleepIntervalMillis; - } - - /** - * Adjusts the audit-completion-interval. Used by JUnit tests. - * @param auditThreadSleepIntervalMillis - */ - protected static void setAuditCompletionIntervalMillis(long auditThreadSleepIntervalMillis) { - AuditThread.auditCompletionIntervalMillis = auditThreadSleepIntervalMillis; - } - - /** - * Gets the audit-completion-interval. Used by JUnit tests. - * @return the current audit-completion interval, in milli-seconds - */ - protected static long getAuditCompletionIntervalMillis() { - return auditCompletionIntervalMillis; - } + private static final Logger logger = FlexLogger.getLogger(AuditThread.class); + + /* + * Number of milliseconds that must elapse for audit to be considered complete. It's public for + * access by JUnit test logic. + */ + public static final long AUDIT_COMPLETION_INTERVAL = 30000; + + /* + * Number of iterations for audit simulation. + */ + public static final long AUDIT_SIMULATION_ITERATIONS = 3; + + /* + * Number of milliseconds to sleep between audit simulation iterations. It's public for access + * by JUnit test logic. + */ + public static final long AUDIT_SIMULATION_SLEEP_INTERVAL = 5000; + + /* + * Unless audit has already been run on this entity, number of milliseconds to sleep between + * audit thread iterations. If audit has already been run, we sleep integrityAuditPeriodMillis. + * May be modified by JUnit tests. + */ + private static long auditThreadSleepIntervalMillis = 5000; + + /* + * Number of milliseconds that must elapse for audit to be considered complete. May be modified + * by JUnit tests. + */ + private static long auditCompletionIntervalMillis = AUDIT_COMPLETION_INTERVAL; + + /* + * DB access class. + */ + private DbDAO dbDao; + + /* + * E.g. pdp_xacml + */ + private String nodeType; + + /* + * Persistence unit for which this audit is being run. + */ + private String persistenceUnit; + + /* + * Name of this resource + */ + private String resourceName; + + /* + * E.g. DB_DRIVER, SITE_NAME, NODE_TYPE + */ + private Properties properties; + + /* + * See IntegrityAudit class for usage. + */ + private long integrityAuditPeriodMillis; + + /* + * The containing IntegrityAudit instance + */ + private IntegrityAudit integrityAudit; + + /** + * A latch is taken from this queue before starting an audit. May be {@code null}. Used by JUnit + * tests. + */ + private BlockingQueue<CountDownLatch> auditLatchQueue; + + /** + * Latch to be decremented when the next audit completes. May be {@code null}. Used by JUnit + * tests to wait for an audit to complete. + */ + private CountDownLatch auditCompletionLatch = null; + + /** + * AuditThread constructor. + * + * @param resourceName the resource name + * @param persistenceUnit the persistence unit + * @param properties the properties + * @param integrityAuditPeriodSeconds the integrity audit period in seconds + * @param integrityAudit the integrity audit + * @throws IntegrityAuditException if an error occurs + */ + public AuditThread(String resourceName, String persistenceUnit, Properties properties, + int integrityAuditPeriodSeconds, IntegrityAudit integrityAudit) throws IntegrityAuditException { + + this(resourceName, persistenceUnit, properties, TimeUnit.SECONDS.toMillis(integrityAuditPeriodSeconds), + integrityAudit, null); + } + + /** + * AuditThread constructor. + * + * @param resourceName the resource name + * @param persistenceUnit the persistence unit + * @param properties the properties + * @param integrityAuditMillis the integrity audit period in milliseconds + * @param integrityAudit the integrity audit + * @param queue the queue + * @throws IntegrityAuditException if an error occurs + */ + public AuditThread(String resourceName, String persistenceUnit, Properties properties, long integrityAuditMillis, + IntegrityAudit integrityAudit, BlockingQueue<CountDownLatch> queue) throws IntegrityAuditException { + this.resourceName = resourceName; + this.persistenceUnit = persistenceUnit; + this.properties = properties; + this.integrityAuditPeriodMillis = integrityAuditMillis; + this.integrityAudit = integrityAudit; + this.auditLatchQueue = queue; + + /* + * The DbDAO Constructor registers this node in the IntegrityAuditEntity table. Each + * resource (node) inserts its own name, persistenceUnit, DB access properties and other + * pertinent properties in the table. This allows the audit on each node to compare its own + * version of the entities for the persistenceUnit in question with the versions from all + * other nodes of similar type. + */ + dbDao = new DbDAO(this.resourceName, this.persistenceUnit, this.properties); + this.nodeType = properties.getProperty(IntegrityAuditProperties.NODE_TYPE); + + } + + @Override + public void run() { + + logger.info("AuditThread.run: Entering"); + + try { + /* + * For JUnit testing: wait for the first latch, decrement it to indicate that the thread + * has started, and then wait for the next latch, before we actually start doing + * anything. These simply return if there is no latch queue defined. + */ + getNextLatch(); + decrementLatch(); + getNextLatch(); + + /* + * Triggers change in designation, unless no other viable candidate. + */ + boolean auditCompleted = false; + + DbAudit dbAudit = new DbAudit(dbDao); + + IntegrityAuditEntity entityCurrentlyDesignated; + IntegrityAuditEntity thisEntity; + integrityAudit.setThreadInitialized(true); // An exception will set it to false + + while (true) { + try { + /* + * It may have been awhile since we last cycled through this loop, so refresh + * the list of IntegrityAuditEntities. + */ + List<IntegrityAuditEntity> integrityAuditEntityList = getIntegrityAuditEntityList(); + + /* + * We could've set entityCurrentlyDesignated as a side effect of + * getIntegrityAuditEntityList(), but then we would've had to make + * entityCurrentlyDesignated a class level attribute. Using this approach, we + * can keep it local to the run() method. + */ + entityCurrentlyDesignated = getEntityCurrentlyDesignated(integrityAuditEntityList); + + /* + * Need to refresh thisEntity each time through loop, because we need a fresh + * version of lastUpdated. + */ + thisEntity = getThisEntity(integrityAuditEntityList); + + /* + * If we haven't done the audit yet, note that we're current and see if we're + * designated. + */ + if (!auditCompleted) { + dbDao.setLastUpdated(); + + /* + * If no current designation or currently designated node is stale, see if + * we're the next node to be designated. + */ + if (entityCurrentlyDesignated == null || isStale(entityCurrentlyDesignated)) { + IntegrityAuditEntity designationCandidate = + getDesignationCandidate(integrityAuditEntityList); + + /* + * If we're the next node to be designated, run the audit. + */ + if (designationCandidate.getResourceName().equals(this.resourceName)) { + runAudit(dbAudit); + auditCompleted = true; + } else { + if (logger.isDebugEnabled()) { + logger.debug("AuditThread.run: designationCandidate, " + + designationCandidate.getResourceName() + ", not this entity, " + + thisEntity.getResourceName()); + } + } + + /* + * Application may have been stopped and restarted, in which case we + * might be designated but auditCompleted will have been reset to false, + * so account for this. + */ + } else if (thisEntity.getResourceName().equals(entityCurrentlyDesignated.getResourceName())) { + + if (logger.isDebugEnabled()) { + logger.debug("AuditThread.run: Re-running audit for " + thisEntity.getResourceName()); + } + runAudit(dbAudit); + auditCompleted = true; + + } else { + if (logger.isDebugEnabled()) { + logger.debug("AuditThread.run: Currently designated node, " + + entityCurrentlyDesignated.getResourceName() + + ", not yet stale and not this node"); + } + } + + + /* + * Audit already completed on this node, so allow the node to go stale until + * twice the AUDIT_COMPLETION_PERIOD has elapsed. This should give plenty of + * time for another node (if another node is out there) to pick up + * designation. + */ + } else { + + auditCompleted = resetAuditCompleted(auditCompleted, thisEntity); + + } + + /* + * If we've just run audit, sleep per the integrity_audit_period_seconds + * property, otherwise just sleep the normal interval. + */ + if (auditCompleted) { + // indicate that an audit has completed + decrementLatch(); + + // don't start the next audit cycle until a latch has been provided + getNextLatch(); + + if (logger.isDebugEnabled()) { + logger.debug("AuditThread.run: Audit completed; resourceName=" + this.resourceName + + " sleeping " + integrityAuditPeriodMillis + "ms"); + } + Thread.sleep(integrityAuditPeriodMillis); + if (logger.isDebugEnabled()) { + logger.debug("AuditThread.run: resourceName=" + this.resourceName + " awaking from " + + integrityAuditPeriodMillis + "ms sleep"); + } + + } else { + + if (logger.isDebugEnabled()) { + logger.debug("AuditThread.run: resourceName=" + this.resourceName + ": Sleeping " + + AuditThread.auditThreadSleepIntervalMillis + "ms"); + } + Thread.sleep(AuditThread.auditThreadSleepIntervalMillis); + if (logger.isDebugEnabled()) { + logger.debug("AuditThread.run: resourceName=" + this.resourceName + ": Awaking from " + + AuditThread.auditThreadSleepIntervalMillis + "ms sleep"); + } + + } + + } catch (Exception e) { + if (isInterruptedException(e)) { + String msg = "AuditThread.run loop - Exception thrown: " + e.getMessage() + "; Stopping."; + logger.error(MessageCodes.EXCEPTION_ERROR, e, msg); + break; + } + + String msg = "AuditThread.run loop - Exception thrown: " + e.getMessage() + + "; Will try audit again in " + (integrityAuditPeriodMillis / 1000) + " seconds"; + logger.error(MessageCodes.EXCEPTION_ERROR, e, msg); + // Sleep and try again later + Thread.sleep(integrityAuditPeriodMillis); + } + + } + + } catch (Exception e) { + String msg = "AuditThread.run: Could not start audit loop. Exception thrown; message=" + e.getMessage(); + logger.error(MessageCodes.EXCEPTION_ERROR, e, msg); + integrityAudit.setThreadInitialized(false); + } + + dbDao.destroy(); + + logger.info("AuditThread.run: Exiting"); + } + + /** + * Gets the next audit-completion latch from the queue. Blocks, if the queue is empty. + * + * @throws InterruptedException if interrupted while waiting + */ + private void getNextLatch() throws InterruptedException { + BlockingQueue<CountDownLatch> queue = this.auditLatchQueue; + if (queue != null) { + this.auditCompletionLatch = queue.take(); + } + } + + /** + * Decrements the current audit-completion latch, if any. + */ + private void decrementLatch() { + CountDownLatch latch = this.auditCompletionLatch; + if (latch != null) { + this.auditCompletionLatch = null; + latch.countDown(); + } + } + + /** + * Determines if an exception is an InterruptedException or was caused by an + * InterruptedException. + * + * @param ex exception to be examined + * @return {@code true} if it's an InterruptedException, {@code false} otherwise + */ + private boolean isInterruptedException(Throwable ex) { + while (ex != null) { + if (ex instanceof InterruptedException) { + return true; + } + + ex = ex.getCause(); + } + + return false; + } + + /* + * Used to create a list that is sorted lexicographically by resourceName. + */ + Comparator<IntegrityAuditEntity> comparator = new Comparator<IntegrityAuditEntity>() { + @Override + public int compare(final IntegrityAuditEntity r1, final IntegrityAuditEntity r2) { + return r1.getResourceName().compareTo(r2.getResourceName()); + } + }; + + /** + * getDesignationCandidate() Using round robin algorithm, gets next candidate to be designated. + * Assumes list is sorted lexicographically by resourceName. + */ + private IntegrityAuditEntity getDesignationCandidate(List<IntegrityAuditEntity> integrityAuditEntityList) { + + // Note: assumes integrityAuditEntityList is already lexicographically sorted by + // resourceName + + if (logger.isDebugEnabled()) { + logger.debug("getDesignationCandidate: Entering, integrityAuditEntityList.size()=" + + integrityAuditEntityList.size()); + } + + IntegrityAuditEntity designationCandidate; + IntegrityAuditEntity thisEntity = null; + + int designatedEntityIndex = -1; + int entityIndex = 0; + int priorCandidateIndex = -1; + int subsequentCandidateIndex = -1; + + for (IntegrityAuditEntity integrityAuditEntity : integrityAuditEntityList) { + + if (logger.isDebugEnabled()) { + logIntegrityAuditEntity(integrityAuditEntity); + } + + if (integrityAuditEntity.getResourceName().equals(this.resourceName)) { + if (logger.isDebugEnabled()) { + logger.debug("getDesignationCandidate: thisEntity=" + integrityAuditEntity.getResourceName()); + } + thisEntity = integrityAuditEntity; + } + + if (integrityAuditEntity.isDesignated()) { + if (logger.isDebugEnabled()) { + logger.debug("getDesignationCandidate: Currently designated entity resourceName=" + + integrityAuditEntity.getResourceName() + ", persistenceUnit=" + + integrityAuditEntity.getPersistenceUnit() + ", lastUpdated=" + + integrityAuditEntity.getLastUpdated() + ", entityIndex=" + entityIndex); + } + designatedEntityIndex = entityIndex; + + /* + * Entity not currently designated + */ + } else { + + /* + * See if non-designated entity is stale. + */ + if (isStale(integrityAuditEntity)) { + + if (logger.isDebugEnabled()) { + logger.debug("getDesignationCandidate: Entity is stale; resourceName=" + + integrityAuditEntity.getResourceName() + ", persistenceUnit=" + + integrityAuditEntity.getPersistenceUnit() + ", lastUpdated=" + + integrityAuditEntity.getLastUpdated() + ", entityIndex=" + entityIndex); + } + + /* + * Entity is current. + */ + } else { + + if (designatedEntityIndex == -1) { + + if (priorCandidateIndex == -1) { + if (logger.isDebugEnabled()) { + logger.debug("getDesignationCandidate: Prior candidate found, resourceName=" + + integrityAuditEntity.getResourceName() + ", persistenceUnit=" + + integrityAuditEntity.getPersistenceUnit() + ", lastUpdated=" + + integrityAuditEntity.getLastUpdated() + ", entityIndex=" + entityIndex); + } + priorCandidateIndex = entityIndex; + } else { + if (logger.isDebugEnabled()) { + logger.debug( + "getDesignationCandidate: Prior entity current but prior candidate already " + + "found; resourceName=" + integrityAuditEntity.getResourceName() + + ", persistenceUnit=" + integrityAuditEntity.getPersistenceUnit() + + ", lastUpdated=" + integrityAuditEntity.getLastUpdated() + + ", entityIndex=" + entityIndex); + } + } + } else { + if (subsequentCandidateIndex == -1) { + if (logger.isDebugEnabled()) { + logger.debug("getDesignationCandidate: Subsequent candidate found, resourceName=" + + integrityAuditEntity.getResourceName() + ", persistenceUnit=" + + integrityAuditEntity.getPersistenceUnit() + ", lastUpdated=" + + integrityAuditEntity.getLastUpdated() + ", entityIndex=" + entityIndex); + } + subsequentCandidateIndex = entityIndex; + } else { + if (logger.isDebugEnabled()) { + logger.debug( + "getDesignationCandidate: Subsequent entity current but subsequent candidate " + + "already found; resourceName=" + + integrityAuditEntity.getResourceName() + ", persistenceUnit=" + + integrityAuditEntity.getPersistenceUnit() + ", lastUpdated=" + + integrityAuditEntity.getLastUpdated() + ", entityIndex=" + + entityIndex); + } + } + } + + } // end entity is current + + } // end entity not currently designated + + entityIndex++; + + } // end for loop + + /* + * Per round robin algorithm, if a current entity is found that is lexicographically after + * the currently designated entity, this entity becomes the designation candidate. If no + * current entity is found that is lexicographically after currently designated entity, we + * cycle back to beginning of list and pick the first current entity as the designation + * candidate. + */ + if (subsequentCandidateIndex != -1) { + designationCandidate = integrityAuditEntityList.get(subsequentCandidateIndex); + if (logger.isDebugEnabled()) { + logger.debug("getDesignationCandidate: Exiting and returning subsequent designationCandidate=" + + designationCandidate.getResourceName()); + } + } else { + if (priorCandidateIndex != -1) { + designationCandidate = integrityAuditEntityList.get(priorCandidateIndex); + if (logger.isDebugEnabled()) { + logger.debug("getDesignationCandidate: Exiting and returning prior designationCandidate=" + + designationCandidate.getResourceName()); + } + } else { + logger.debug("getDesignationCandidate: No subsequent or prior candidate found; designating thisEntity, " + + "resourceName=" + thisEntity.getResourceName()); + designationCandidate = thisEntity; + } + } + + return designationCandidate; + + } + + /** + * getEntityCurrentlyDesignated() Returns entity that is currently designated. + * + * @param integrityAuditEntityList the integrity audit entity list + * @return the currently designated integrity audit entity + */ + private IntegrityAuditEntity getEntityCurrentlyDesignated(List<IntegrityAuditEntity> integrityAuditEntityList) { + + if (logger.isDebugEnabled()) { + logger.debug("getEntityCurrentlyDesignated: Entering, integrityAuditEntityList.size=" + + integrityAuditEntityList.size()); + } + + IntegrityAuditEntity entityCurrentlyDesignated = null; + + for (IntegrityAuditEntity integrityAuditEntity : integrityAuditEntityList) { + + if (integrityAuditEntity.isDesignated()) { + if (logger.isDebugEnabled()) { + logger.debug("getEntityCurrentlyDesignated: Currently designated entity resourceName=" + + integrityAuditEntity.getResourceName() + ", persistenceUnit=" + + integrityAuditEntity.getPersistenceUnit() + ", lastUpdated=" + + integrityAuditEntity.getLastUpdated()); + } + entityCurrentlyDesignated = integrityAuditEntity; + } + + } // end for loop + + if (logger.isDebugEnabled()) { + if (entityCurrentlyDesignated != null) { + logger.debug("getEntityCurrentlyDesignated: Exiting and returning entityCurrentlyDesignated=" + + entityCurrentlyDesignated.getResourceName()); + } else { + logger.debug("getEntityCurrentlyDesignated: Exiting and returning entityCurrentlyDesignated=" + + entityCurrentlyDesignated); + } + } + return entityCurrentlyDesignated; + + } + + /** + * getIntegrityAuditEnityList gets the list of IntegrityAuditEntity. + * + * @return the list of IntegrityAuditEntity + * @throws DbDaoTransactionException if an error occurs getting the list of IntegrityAuditEntity + */ + private List<IntegrityAuditEntity> getIntegrityAuditEntityList() throws DbDaoTransactionException { + + if (logger.isDebugEnabled()) { + logger.debug("getIntegrityAuditEntityList: Entering"); + } + + /* + * Get all records for this nodeType and persistenceUnit and then sort them + * lexicographically by resourceName. Get index of designated entity, if any. + */ + /* + * Sorted list of entities for a particular nodeType and persistenceUnit. + */ + List<IntegrityAuditEntity> integrityAuditEntityList = + dbDao.getIntegrityAuditEntities(this.persistenceUnit, this.nodeType); + int listSize = integrityAuditEntityList.size(); + if (logger.isDebugEnabled()) { + logger.debug("getIntegrityAuditEntityList: Got " + listSize + " IntegrityAuditEntity records"); + } + Collections.sort(integrityAuditEntityList, comparator); + + if (logger.isDebugEnabled()) { + logger.debug( + "getIntegrityAuditEntityList: Exiting and returning integrityAuditEntityList, size=" + listSize); + } + return integrityAuditEntityList; + + } + + + /** + * Returns the IntegrityAuditEntity for this entity. + * + * @param integrityAuditEntityList the list of IntegrityAuditEntity + * @return the IntegrityAuditEntity for this entity + */ + private IntegrityAuditEntity getThisEntity(List<IntegrityAuditEntity> integrityAuditEntityList) { + + if (logger.isDebugEnabled()) { + logger.debug("getThisEntity: Entering, integrityAuditEntityList.size=" + integrityAuditEntityList.size()); + } + + IntegrityAuditEntity thisEntity = null; + + for (IntegrityAuditEntity integrityAuditEntity : integrityAuditEntityList) { + + if (integrityAuditEntity.getResourceName().equals(this.resourceName)) { + if (logger.isDebugEnabled()) { + logger.debug( + "getThisEntity: For this entity, resourceName=" + integrityAuditEntity.getResourceName() + + ", persistenceUnit=" + integrityAuditEntity.getPersistenceUnit() + + ", lastUpdated=" + integrityAuditEntity.getLastUpdated()); + } + thisEntity = integrityAuditEntity; + } + + } // end for loop + + if (logger.isDebugEnabled()) { + if (thisEntity != null) { + logger.debug("getThisEntity: Exiting and returning thisEntity=" + thisEntity.getResourceName()); + } else { + logger.debug("getThisEntity: Exiting and returning thisEntity=" + thisEntity); + } + } + return thisEntity; + + } + + + /** + * Returns false if the lastUpdated time for the record in question is more than + * auditCompletionIntervalMillis seconds ago. During an audit, lastUpdated is updated every five + * seconds or so, but when an audit finishes, the node doing the audit stops updating + * lastUpdated. + * + * @param integrityAuditEntity the integrityAuditEntity + * @return false if the lastUpdated time for the record in question is more than + * auditCompletionIntervalMillis seconds ago + */ + private boolean isStale(IntegrityAuditEntity integrityAuditEntity) { + + if (logger.isDebugEnabled()) { + logger.debug("isStale: Entering, resourceName=" + integrityAuditEntity.getResourceName() + + ", persistenceUnit=" + integrityAuditEntity.getPersistenceUnit() + ", lastUpdated=" + + integrityAuditEntity.getLastUpdated()); + } + + boolean stale = false; + + Date currentTime = new Date(); + Date lastUpdated = integrityAuditEntity.getLastUpdated(); + + /* + * If lastUpdated is null, we assume that the audit never ran for that node. + */ + long lastUpdatedTime = 0; + if (lastUpdated != null) { + lastUpdatedTime = lastUpdated.getTime(); + } + long timeDifference = currentTime.getTime() - lastUpdatedTime; + if (timeDifference > auditCompletionIntervalMillis) { + stale = true; + } + + if (logger.isDebugEnabled()) { + logger.debug("isStale: Exiting and returning stale=" + stale + ", timeDifference=" + timeDifference); + } + + return stale; + } + + private void logIntegrityAuditEntity(IntegrityAuditEntity integrityAuditEntity) { + + logger.debug("logIntegrityAuditEntity: id=" + integrityAuditEntity.getId() + ", jdbcDriver=" + + integrityAuditEntity.getJdbcDriver() + ", jdbcPassword=" + integrityAuditEntity.getJdbcPassword() + + ", jdbcUrl=" + integrityAuditEntity.getJdbcUrl() + ", jdbcUser=" + integrityAuditEntity.getJdbcUser() + + ", nodeType=" + integrityAuditEntity.getNodeType() + ", persistenceUnit=" + + integrityAuditEntity.getPersistenceUnit() + ", resourceName=" + integrityAuditEntity.getResourceName() + + ", site=" + integrityAuditEntity.getSite() + ", createdDate=" + integrityAuditEntity.getCreatedDate() + + ", lastUpdated=" + integrityAuditEntity.getLastUpdated() + ", designated=" + + integrityAuditEntity.isDesignated()); + } + + /* + * If more than (auditCompletionIntervalMillis * 2) milliseconds have elapsed since we last ran + * the audit, reset auditCompleted, so + * + * 1) we'll eventually re-run the audit, if no other node picks up the designation. + * + * or + * + * 2) We'll run the audit when the round robin comes back to us. + */ + private boolean resetAuditCompleted(boolean auditCompleted, IntegrityAuditEntity thisEntity) { + + if (logger.isDebugEnabled()) { + logger.debug("resetAuditCompleted: auditCompleted=" + auditCompleted + "; for thisEntity, resourceName=" + + thisEntity.getResourceName() + ", persistenceUnit=" + thisEntity.getPersistenceUnit() + + ", lastUpdated=" + thisEntity.getLastUpdated()); + } + + long timeDifference; + + Date currentTime = new Date(); + Date lastUpdated = thisEntity.getLastUpdated(); + + long lastUpdatedTime = lastUpdated.getTime(); + timeDifference = currentTime.getTime() - lastUpdatedTime; + + if (timeDifference > (auditCompletionIntervalMillis * 2)) { + if (logger.isDebugEnabled()) { + logger.debug("resetAuditCompleted: Resetting auditCompleted for resourceName=" + this.resourceName); + } + auditCompleted = false; + } else { + if (logger.isDebugEnabled()) { + logger.debug( + "resetAuditCompleted: For resourceName=" + resourceName + ", time since last update is only " + + timeDifference + "; retaining current value for auditCompleted"); + } + } + + if (logger.isDebugEnabled()) { + logger.debug("resetAuditCompleted: Exiting and returning auditCompleted=" + auditCompleted + + ", timeDifference=" + timeDifference); + } + return auditCompleted; + } + + private void runAudit(DbAudit dbAudit) throws IntegrityAuditException { + + if (logger.isDebugEnabled()) { + logger.debug("runAudit: Entering, dbAudit=" + dbAudit + "; notifying other resources that resourceName=" + + this.resourceName + " is current"); + } + + /* + * changeDesignated marks all other nodes as non-designated and this node as designated. + */ + dbDao.changeDesignated(this.resourceName, this.persistenceUnit, this.nodeType); + + if (logger.isDebugEnabled()) { + logger.debug("runAudit: Running audit for persistenceUnit=" + this.persistenceUnit + " on resourceName=" + + this.resourceName); + } + if (IntegrityAudit.isUnitTesting()) { + dbAudit.dbAuditSimulate(this.resourceName, this.persistenceUnit, AuditThread.AUDIT_SIMULATION_ITERATIONS, + AuditThread.auditThreadSleepIntervalMillis); + } else { + dbAudit.dbAudit(this.resourceName, this.persistenceUnit, this.nodeType); + } + + if (logger.isDebugEnabled()) { + logger.debug("runAudit: Exiting"); + } + + } + + /** + * Adjusts the thread-sleep-interval to be used when an audit has <i>not</i> been completed. + * Used by JUnit tests. + * + * @param auditThreadSleepIntervalMillis the interval to use in milliseconds + */ + protected static void setAuditThreadSleepIntervalMillis(long auditThreadSleepIntervalMillis) { + AuditThread.auditThreadSleepIntervalMillis = auditThreadSleepIntervalMillis; + } + + /** + * Gets the current thread-sleep-interval to be used when an audit has <i>not</i> been + * completed. Used by JUnit tests. + * + * @return the current sleep interval, in milli-seconds + */ + protected static long getAuditThreadSleepIntervalMillis() { + return auditThreadSleepIntervalMillis; + } + + /** + * Adjusts the audit-completion-interval. Used by JUnit tests. + * + * @param auditThreadSleepIntervalMillis the interval to use in milliseconds + */ + protected static void setAuditCompletionIntervalMillis(long auditThreadSleepIntervalMillis) { + AuditThread.auditCompletionIntervalMillis = auditThreadSleepIntervalMillis; + } + + /** + * Gets the audit-completion-interval. Used by JUnit tests. + * + * @return the current audit-completion interval, in milli-seconds + */ + protected static long getAuditCompletionIntervalMillis() { + return auditCompletionIntervalMillis; + } } diff --git a/integrity-audit/src/main/java/org/onap/policy/common/ia/DbAudit.java b/integrity-audit/src/main/java/org/onap/policy/common/ia/DbAudit.java index 6fb619e4..4c4104f6 100644 --- a/integrity-audit/src/main/java/org/onap/policy/common/ia/DbAudit.java +++ b/integrity-audit/src/main/java/org/onap/policy/common/ia/DbAudit.java @@ -36,492 +36,501 @@ import org.apache.commons.lang3.SerializationUtils; import org.apache.commons.lang3.builder.RecursiveToStringStyle; import org.apache.commons.lang3.builder.ReflectionToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; - - - - - import org.onap.policy.common.ia.jpa.IntegrityAuditEntity; import org.onap.policy.common.logging.eelf.MessageCodes; -import org.onap.policy.common.logging.flexlogger.FlexLogger; +import org.onap.policy.common.logging.flexlogger.FlexLogger; import org.onap.policy.common.logging.flexlogger.Logger; /** * class DbAudit does actual auditing of DB tables. */ public class DbAudit { - - private static final Logger logger = FlexLogger.getLogger(DbAudit.class); - - private static long dbAuditUpdateMillis = 5000l; - private static long dbAuditSleepMillis = 2000l; - - DbDAO dbDAO = null; - - public DbAudit(DbDAO dbDAO) { - - if (logger.isDebugEnabled()) { - logger.debug("Constructor: Entering"); - } - - this.dbDAO = dbDAO; - - if (logger.isDebugEnabled()) { - logger.debug("Constructor: Exiting"); - } - - } - - /** - * dbAudit actually does the audit - * @param resourceName - * @param persistenceUnit - * @param nodeType - * @throws Exception - */ - public void dbAudit(String resourceName, String persistenceUnit, String nodeType) throws IntegrityAuditException { - - if (logger.isDebugEnabled()) { - logger.debug("dbAudit: Entering, resourceName=" + resourceName - + ", persistenceUnit=" + persistenceUnit + ", nodeType=" - + nodeType); - } - - // Get all IntegrityAudit entries so we can get the DB access info - List<IntegrityAuditEntity> iaeList = dbDAO.getIntegrityAuditEntities(persistenceUnit, nodeType); - if(iaeList == null || iaeList.isEmpty()){ - - String msg = "DbAudit: for node " + resourceName + " Found no IntegrityAuditEntity entries"; - logger.error(MessageCodes.ERROR_AUDIT, msg); - throw new DbAuditException(msg); - - }else if(iaeList.size() == 1){ - - Long iaeId = null; - String iaeRN = null; - String iaeNT = null; - String iaeS = null; - for (IntegrityAuditEntity iae : iaeList){ - iaeId = iae.getId(); - iaeRN = iae.getResourceName(); - iaeNT = iae.getNodeType(); - iaeS = iae.getSite(); - } - String msg = "DbAudit: Found only one IntegrityAuditEntity entry:" - + " ID = " + iaeId - + " ResourceName = " + iaeRN - + " NodeType = " + iaeNT - + " Site = " + iaeS; - logger.warn(msg); - return; - } - - // Obtain all persistence class names for the PU we are auditing - Set<String> classNameSet = dbDAO.getPersistenceClassNames(); - if(classNameSet == null || classNameSet.isEmpty()){ - - String msg = "DbAudit: For node " + resourceName + " Found no persistence class names"; - logger.error(MessageCodes.ERROR_AUDIT, msg); - throw new DbAuditException(msg); - - } - - /* - * Retrieve myIae. We are going to compare the local class entries against - * all other DB nodes. Since the audit is run in a round-robin, every instance - * will be compared against every other instance. - */ - IntegrityAuditEntity myIae = dbDAO.getMyIntegrityAuditEntity(); - - if(myIae == null){ - - String msg = "DbAudit: Found no IntegrityAuditEntity entry for resourceName: " + resourceName - + " persistenceUnit: " + persistenceUnit; - logger.error(MessageCodes.ERROR_AUDIT, msg); - throw new DbAuditException(msg); - - } - /* - * This is the map of mismatched entries indexed by className. For - * each class name there is a list of mismatched entries - */ - Map<String,Set<Object>> misMatchedMap = new HashMap<>(); - - // We need to keep track of how long the audit is taking - long startTime = System.currentTimeMillis(); - - // Retrieve all instances of the class for each node - if (logger.isDebugEnabled()) { - logger.debug("dbAudit: Traversing classNameSet, size=" + classNameSet.size()); - } - for(String clazzName: classNameSet){ - - if (logger.isDebugEnabled()) { - logger.debug("dbAudit: clazzName=" + clazzName); - } - - // all instances of the class for myIae - Map<Object,Object> myEntries = dbDAO.getAllMyEntries(clazzName); - //get a map of the objects indexed by id. Does not necessarily have any entries - - if (logger.isDebugEnabled()) { - logger.debug("dbAudit: Traversing iaeList, size=" + iaeList.size()); - } - for (IntegrityAuditEntity iae : iaeList){ - if(iae.getId() == myIae.getId()){ - if (logger.isDebugEnabled()) { - logger.debug("dbAudit: My Id=" + iae.getId() - + ", resourceName=" + iae.getResourceName()); - } - continue; //no need to compare with self - } else { - if (logger.isDebugEnabled()) { - logger.debug("dbAudit: Id=" + iae.getId() - + ", resourceName=" + iae.getResourceName()); - } - } - // Create properties for the other db node - Properties theirProperties = new Properties(); - theirProperties.put(IntegrityAuditProperties.DB_DRIVER, iae.getJdbcDriver()); - theirProperties.put(IntegrityAuditProperties.DB_URL, iae.getJdbcUrl()); - theirProperties.put(IntegrityAuditProperties.DB_USER, iae.getJdbcUser()); - theirProperties.put(IntegrityAuditProperties.DB_PWD, iae.getJdbcPassword()); - theirProperties.put(IntegrityAuditProperties.SITE_NAME, iae.getSite()); - theirProperties.put(IntegrityAuditProperties.NODE_TYPE, iae.getNodeType()); - - //get a map of the instances for their iae indexed by id - Map<Object,Object> theirEntries = dbDAO.getAllEntries(persistenceUnit, theirProperties, clazzName); - if (logger.isDebugEnabled()) { - logger.debug("dbAudit: For persistenceUnit=" - + persistenceUnit + ", clazzName=" + clazzName - + ", theirEntries.size()=" - + theirEntries.size()); - } - - /* - * Compare myEntries with theirEntries and get back a set of mismatched IDs. - * Collect the IDs for the class where a mismatch occurred. We will check - * them again for all nodes later. - */ - Set<Object> misMatchedKeySet = compareEntries(myEntries, theirEntries); - if(!misMatchedKeySet.isEmpty()){ - Set<Object> misMatchedEntry = misMatchedMap.get(clazzName); - if(misMatchedEntry == null){ - misMatchedMap.put(clazzName, misMatchedKeySet); - }else{ - misMatchedEntry.addAll(misMatchedKeySet); - misMatchedMap.put(clazzName, misMatchedEntry); - } - } - } //end for (IntegrityAuditEntity iae : iaeList) - //Time check - if((System.currentTimeMillis() - startTime) >= dbAuditUpdateMillis){ - //update the timestamp - dbDAO.setLastUpdated(); - //reset the startTime - startTime=System.currentTimeMillis(); - }else{ - //sleep a couple seconds to break up the activity - if (logger.isDebugEnabled()) { - logger.debug("dbAudit: Sleeping " + dbAuditSleepMillis + "ms"); - } - sleep(); - if (logger.isDebugEnabled()) { - logger.debug("dbAudit: Waking from sleep"); - } - } - }//end: for(String clazzName: classNameList) - - //check if misMatchedMap is empty - if(misMatchedMap.isEmpty()){ - - if (logger.isDebugEnabled()) { - logger.debug("dbAudit: Exiting, misMatchedMap is empty"); - } - //we are done - return; - } else { - if (logger.isDebugEnabled()) { - logger.debug("dbAudit: Doing another comparison; misMatchedMap.size()=" + misMatchedMap.size()); - } - } - - // If misMatchedMap is not empty, retrieve the entries in each misMatched list and compare again - classNameSet = new HashSet<>(misMatchedMap.keySet()); - // We need to keep track of how long the audit is taking - startTime = System.currentTimeMillis(); - - // Retrieve all instances of the class for each node - if (logger.isDebugEnabled()) { - logger.debug("dbAudit: Second comparison; traversing classNameSet, size=" + classNameSet.size()); - } - - int errorCount = 0; - - for(String clazzName: classNameSet){ - - if (logger.isDebugEnabled()) { - logger.debug("dbAudit: Second comparison; clazzName=" + clazzName); - } - - // all instances of the class for myIae - Set<Object> keySet = misMatchedMap.get(clazzName); - Map<Object,Object> myEntries = dbDAO.getAllMyEntries(clazzName, keySet); - //get a map of the objects indexed by id - - if (logger.isDebugEnabled()) { - logger.debug("dbAudit: Second comparison; traversing iaeList, size=" + iaeList.size()); - } - for (IntegrityAuditEntity iae : iaeList){ - if(iae.getId() == myIae.getId()){ - if (logger.isDebugEnabled()) { - logger.debug("dbAudit: Second comparison; My Id=" + iae.getId() - + ", resourceName=" + iae.getResourceName()); - } - continue; //no need to compare with self - } else { - if (logger.isDebugEnabled()) { - logger.debug("dbAudit: Second comparison; Id=" + iae.getId() - + ", resourceName=" + iae.getResourceName()); - } - } - // Create properties for the other db node - Properties theirProperties = new Properties(); - theirProperties.put(IntegrityAuditProperties.DB_DRIVER, iae.getJdbcDriver()); - theirProperties.put(IntegrityAuditProperties.DB_URL, iae.getJdbcUrl()); - theirProperties.put(IntegrityAuditProperties.DB_USER, iae.getJdbcUser()); - theirProperties.put(IntegrityAuditProperties.DB_PWD, iae.getJdbcPassword()); - theirProperties.put(IntegrityAuditProperties.SITE_NAME, iae.getSite()); - theirProperties.put(IntegrityAuditProperties.NODE_TYPE, iae.getNodeType()); - - //get a map of the instances for their iae indexed by id - Map<Object,Object> theirEntries = dbDAO.getAllEntries(persistenceUnit, theirProperties, clazzName, keySet); - - /* - * Compare myEntries with theirEntries and get back a set of mismatched IDs. - * Collect the IDs for the class where a mismatch occurred. We will now - * write an error log for each. - */ - Set<Object> misMatchedKeySet = compareEntries(myEntries, theirEntries); - if(!misMatchedKeySet.isEmpty()){ - String keysString = ""; - for(Object key: misMatchedKeySet){ - keysString = keysString.concat(key.toString() + ", "); - errorCount ++; - } - writeAuditSummaryLog(clazzName, resourceName, iae.getResourceName(), keysString); - if(logger.isDebugEnabled()){ - for(Object key : misMatchedKeySet){ - writeAuditDebugLog(clazzName, resourceName, iae.getResourceName(), myEntries.get(key), theirEntries.get(key)); - } - } - } - } - //Time check - if((System.currentTimeMillis() - startTime) >= dbAuditUpdateMillis){ - //update the timestamp - dbDAO.setLastUpdated(); - //reset the startTime - startTime=System.currentTimeMillis(); - }else{ - //sleep a couple seconds to break up the activity - if (logger.isDebugEnabled()) { - logger.debug("dbAudit: Second comparison; sleeping " + dbAuditSleepMillis + "ms"); - } - sleep(); - if (logger.isDebugEnabled()) { - logger.debug("dbAudit: Second comparison; waking from sleep"); - } - } - }//end: for(String clazzName: classNameList) - - if(errorCount != 0){ - String msg = " DB Audit: " + errorCount + " errors found. A large number of errors may indicate DB replication has stopped"; - logger.error(MessageCodes.ERROR_AUDIT, msg); - } - - if (logger.isDebugEnabled()) { - logger.debug("dbAudit: Exiting"); - } - - return; //all done - } - - /** - * Sleeps a bit. - * @throws IntegrityAuditException - */ - private void sleep() throws IntegrityAuditException { - try { - Thread.sleep(dbAuditSleepMillis); - - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw new IntegrityAuditException(e); - } - } - - /** - * dbAuditSimulate simulates the DB audit - * @param resourceName - * @param persistenceUnit - * @param simulationIterations - * @param simulationIntervalMs - * @param nodeType - * @throws DbAuditException - */ - public void dbAuditSimulate(String resourceName, String persistenceUnit, long simulationIterations, long simulationIntervalMs) throws DbAuditException { - - try { - logger.info("dbAuditSimulate: Starting audit simulation for resourceName=" - + resourceName + ", persistenceUnit=" + persistenceUnit); - - for (int i = 0; i < simulationIterations; i++) { - dbDAO.setLastUpdated(); - logger.info("dbAuditSimulate: i=" + i + ", sleeping " - + simulationIntervalMs + "ms"); - Thread.sleep(simulationIntervalMs); - } - - logger.info("dbAuditSimulate: Finished audit simulation for resourceName=" - + resourceName + ", persistenceUnit=" + persistenceUnit); - - } catch(DbDaoTransactionException e) { - throw new DbAuditException(e); - - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw new DbAuditException(e); - } - } - - /** - * compareEntries() will compare the lists of entries from the DB - * @param myEntries - * @param theirEntries - * @return - */ - public Set<Object> compareEntries(Map<Object,Object> myEntries, Map<Object,Object> theirEntries){ - /* - * Compare the entries for the same key in each of the hashmaps. The comparison will be done by serializing the objects - * (create a byte array) and then do a byte array comparison. The audit will walk the local repository hash map comparing - * to the remote cluster hashmap and then turn it around and walk the remote hashmap and look for any entries that are not - * present in the local cluster hashmap. - * - * If the objects are not identical, the audit will put the object IDs on a list to try after completing the audit of the table - * it is currently working on. - * - */ - HashSet<Object> misMatchedKeySet = new HashSet<>(); - for(Entry<Object, Object> ent: myEntries.entrySet()) { - Object key = ent.getKey(); - byte[] mySerializedEntry = SerializationUtils.serialize((Serializable) ent.getValue()); - byte[] theirSerializedEntry = SerializationUtils.serialize((Serializable) theirEntries.get(key)); - if(!Arrays.equals(mySerializedEntry, theirSerializedEntry)){ - logger.debug("compareEntries: For myEntries.key=" + key + ", entries do not match"); - misMatchedKeySet.add(key); - } else { - logger.debug("compareEntries: For myEntries.key=" + key + ", entries match"); - } - } - //now compare it in the other direction to catch entries in their set that is not in my set - for(Entry<Object, Object> ent: theirEntries.entrySet()) { - Object key = ent.getKey(); - byte[] mySerializedEntry = SerializationUtils.serialize((Serializable) myEntries.get(key)); - byte[] theirSerializedEntry = SerializationUtils.serialize((Serializable) ent.getValue()); - if(!Arrays.equals(mySerializedEntry, theirSerializedEntry)){ - logger.debug("compareEntries: For theirEntries.key=" + key + ", entries do not match"); - misMatchedKeySet.add(key); - } else { - logger.debug("compareEntries: For theirEntries.key=" + key + ", entries match"); - } - } - - //return a Set of the object IDs - logger.debug("compareEntries: misMatchedKeySet.size()=" + misMatchedKeySet.size()); - return misMatchedKeySet; - } - - /** - * writeAuditDebugLog() writes the mismatched entry details to the debug log - * @param clazzName - * @param resourceName1 - * @param resourceName2 - * @param entry1 - * @param entry2 - * @throws IntegrityAuditException - */ - public void writeAuditDebugLog(String clazzName, String resourceName1, - String resourceName2, Object entry1, Object entry2) throws IntegrityAuditException{ - try { - Class<?> entityClass = Class.forName(clazzName); - String tableName = entityClass.getAnnotation(Table.class).name(); - String msg = "\nDB Audit Error: " - + "\n Table Name: " + tableName - + "\n Entry 1 (short prefix style): " + resourceName1 + ": " + new ReflectionToStringBuilder(entry1,ToStringStyle.SHORT_PREFIX_STYLE).toString() - + "\n Entry 2 (short prefix style): " + resourceName2 + ": " + new ReflectionToStringBuilder(entry2,ToStringStyle.SHORT_PREFIX_STYLE).toString() - + "\n Entry 1 (recursive style): " + resourceName1 + ": " + new ReflectionToStringBuilder(entry1, new RecursiveToStringStyle()).toString() - + "\n Entry 2 (recursive style): " + resourceName2 + ": " + new ReflectionToStringBuilder(entry2, new RecursiveToStringStyle()).toString(); - logger.debug(msg); - - } catch (ClassNotFoundException e) { - throw new IntegrityAuditException(e); - } - - } - - /** - * writeAuditSummaryLog() writes a summary of the DB mismatches to the error log - * @param clazzName - * @param resourceName1 - * @param resourceName2 - * @param keys - * @throws IntegrityAuditException - */ - public void writeAuditSummaryLog(String clazzName, String resourceName1, - String resourceName2, String keys) throws IntegrityAuditException{ - try { - Class<?> entityClass = Class.forName(clazzName); - String tableName = entityClass.getAnnotation(Table.class).name(); - String msg = " DB Audit Error: Table Name: " + tableName - + "; Mismatch between nodes: " + resourceName1 +" and " + resourceName2 - + "; Mismatched entries (keys): " + keys; - logger.info(msg); - } catch (ClassNotFoundException e) { - throw new IntegrityAuditException(e); - } - } - - /** - * Gets the audit-update time. - * @return the audit-update time, in milliseconds - */ - protected static long getDbAuditUpdateMillis() { - return dbAuditUpdateMillis; - } - - /** - * Sets the audit-update time. - * @param dbAuditUpdateMillis the new audit update time, in milliseconds - */ - protected static void setDbAuditUpdateMillis(long dbAuditUpdateMillis) { - DbAudit.dbAuditUpdateMillis = dbAuditUpdateMillis; - } - - /** - * Gets the audit-sleep time. - * @return the audit-sleep time, in milliseconds - */ - protected static long getDbAuditSleepMillis() { - return dbAuditSleepMillis; - } - - /** - * Sets the audit-sleep time. - * @param dbAuditSleepMillis the new audit sleep time, in milliseconds - */ - protected static void setDbAuditSleepMillis(long dbAuditSleepMillis) { - DbAudit.dbAuditSleepMillis = dbAuditSleepMillis; - } + + private static final Logger logger = FlexLogger.getLogger(DbAudit.class); + + private static long dbAuditUpdateMillis = 5000L; + private static long dbAuditSleepMillis = 2000L; + + DbDAO dbDao = null; + + /** + * Construct an instance with the given DbDAO. + * + * @param dbDao the DbDAO + */ + public DbAudit(DbDAO dbDao) { + + if (logger.isDebugEnabled()) { + logger.debug("Constructor: Entering"); + } + + this.dbDao = dbDao; + + if (logger.isDebugEnabled()) { + logger.debug("Constructor: Exiting"); + } + + } + + /** + * dbAudit actually does the audit. + * + * @param resourceName the resource name + * @param persistenceUnit the persistence unit + * @param nodeType the node type + * @throws IntegrityAuditException if an error occurs + */ + public void dbAudit(String resourceName, String persistenceUnit, String nodeType) throws IntegrityAuditException { + + if (logger.isDebugEnabled()) { + logger.debug("dbAudit: Entering, resourceName=" + resourceName + ", persistenceUnit=" + persistenceUnit + + ", nodeType=" + nodeType); + } + + // Get all IntegrityAudit entries so we can get the DB access info + List<IntegrityAuditEntity> iaeList = dbDao.getIntegrityAuditEntities(persistenceUnit, nodeType); + if (iaeList == null || iaeList.isEmpty()) { + + String msg = "DbAudit: for node " + resourceName + " Found no IntegrityAuditEntity entries"; + logger.error(MessageCodes.ERROR_AUDIT, msg); + throw new DbAuditException(msg); + + } else if (iaeList.size() == 1) { + + Long iaeId = null; + String iaeRn = null; + String iaeNt = null; + String iaeS = null; + for (IntegrityAuditEntity iae : iaeList) { + iaeId = iae.getId(); + iaeRn = iae.getResourceName(); + iaeNt = iae.getNodeType(); + iaeS = iae.getSite(); + } + String msg = "DbAudit: Found only one IntegrityAuditEntity entry:" + " ID = " + iaeId + " ResourceName = " + + iaeRn + " NodeType = " + iaeNt + " Site = " + iaeS; + logger.warn(msg); + return; + } + + // Obtain all persistence class names for the PU we are auditing + Set<String> classNameSet = dbDao.getPersistenceClassNames(); + if (classNameSet == null || classNameSet.isEmpty()) { + + String msg = "DbAudit: For node " + resourceName + " Found no persistence class names"; + logger.error(MessageCodes.ERROR_AUDIT, msg); + throw new DbAuditException(msg); + + } + + /* + * Retrieve myIae. We are going to compare the local class entries against all other DB + * nodes. Since the audit is run in a round-robin, every instance will be compared against + * every other instance. + */ + IntegrityAuditEntity myIae = dbDao.getMyIntegrityAuditEntity(); + + if (myIae == null) { + + String msg = "DbAudit: Found no IntegrityAuditEntity entry for resourceName: " + resourceName + + " persistenceUnit: " + persistenceUnit; + logger.error(MessageCodes.ERROR_AUDIT, msg); + throw new DbAuditException(msg); + + } + /* + * This is the map of mismatched entries indexed by className. For each class name there is + * a list of mismatched entries + */ + Map<String, Set<Object>> misMatchedMap = new HashMap<>(); + + // We need to keep track of how long the audit is taking + long startTime = System.currentTimeMillis(); + + // Retrieve all instances of the class for each node + if (logger.isDebugEnabled()) { + logger.debug("dbAudit: Traversing classNameSet, size=" + classNameSet.size()); + } + for (String clazzName : classNameSet) { + + if (logger.isDebugEnabled()) { + logger.debug("dbAudit: clazzName=" + clazzName); + } + + // all instances of the class for myIae + Map<Object, Object> myEntries = dbDao.getAllMyEntries(clazzName); + // get a map of the objects indexed by id. Does not necessarily have any entries + + if (logger.isDebugEnabled()) { + logger.debug("dbAudit: Traversing iaeList, size=" + iaeList.size()); + } + for (IntegrityAuditEntity iae : iaeList) { + if (iae.getId() == myIae.getId()) { + if (logger.isDebugEnabled()) { + logger.debug("dbAudit: My Id=" + iae.getId() + ", resourceName=" + iae.getResourceName()); + } + continue; // no need to compare with self + } else { + if (logger.isDebugEnabled()) { + logger.debug("dbAudit: Id=" + iae.getId() + ", resourceName=" + iae.getResourceName()); + } + } + // Create properties for the other db node + Properties theirProperties = new Properties(); + theirProperties.put(IntegrityAuditProperties.DB_DRIVER, iae.getJdbcDriver()); + theirProperties.put(IntegrityAuditProperties.DB_URL, iae.getJdbcUrl()); + theirProperties.put(IntegrityAuditProperties.DB_USER, iae.getJdbcUser()); + theirProperties.put(IntegrityAuditProperties.DB_PWD, iae.getJdbcPassword()); + theirProperties.put(IntegrityAuditProperties.SITE_NAME, iae.getSite()); + theirProperties.put(IntegrityAuditProperties.NODE_TYPE, iae.getNodeType()); + + // get a map of the instances for their iae indexed by id + Map<Object, Object> theirEntries = dbDao.getAllEntries(persistenceUnit, theirProperties, clazzName); + if (logger.isDebugEnabled()) { + logger.debug("dbAudit: For persistenceUnit=" + persistenceUnit + ", clazzName=" + clazzName + + ", theirEntries.size()=" + theirEntries.size()); + } + + /* + * Compare myEntries with theirEntries and get back a set of mismatched IDs. Collect + * the IDs for the class where a mismatch occurred. We will check them again for all + * nodes later. + */ + Set<Object> misMatchedKeySet = compareEntries(myEntries, theirEntries); + if (!misMatchedKeySet.isEmpty()) { + Set<Object> misMatchedEntry = misMatchedMap.get(clazzName); + if (misMatchedEntry == null) { + misMatchedMap.put(clazzName, misMatchedKeySet); + } else { + misMatchedEntry.addAll(misMatchedKeySet); + misMatchedMap.put(clazzName, misMatchedEntry); + } + } + } // end for (IntegrityAuditEntity iae : iaeList) + + // Time check + if ((System.currentTimeMillis() - startTime) >= dbAuditUpdateMillis) { + // update the timestamp + dbDao.setLastUpdated(); + // reset the startTime + startTime = System.currentTimeMillis(); + } else { + // sleep a couple seconds to break up the activity + if (logger.isDebugEnabled()) { + logger.debug("dbAudit: Sleeping " + dbAuditSleepMillis + "ms"); + } + sleep(); + if (logger.isDebugEnabled()) { + logger.debug("dbAudit: Waking from sleep"); + } + } + } // end: for(String clazzName: classNameList) + + // check if misMatchedMap is empty + if (misMatchedMap.isEmpty()) { + + if (logger.isDebugEnabled()) { + logger.debug("dbAudit: Exiting, misMatchedMap is empty"); + } + // we are done + return; + } else { + if (logger.isDebugEnabled()) { + logger.debug("dbAudit: Doing another comparison; misMatchedMap.size()=" + misMatchedMap.size()); + } + } + + // If misMatchedMap is not empty, retrieve the entries in each misMatched list and compare + // again + classNameSet = new HashSet<>(misMatchedMap.keySet()); + // We need to keep track of how long the audit is taking + startTime = System.currentTimeMillis(); + + // Retrieve all instances of the class for each node + if (logger.isDebugEnabled()) { + logger.debug("dbAudit: Second comparison; traversing classNameSet, size=" + classNameSet.size()); + } + + int errorCount = 0; + + for (String clazzName : classNameSet) { + + if (logger.isDebugEnabled()) { + logger.debug("dbAudit: Second comparison; clazzName=" + clazzName); + } + + // all instances of the class for myIae + Set<Object> keySet = misMatchedMap.get(clazzName); + Map<Object, Object> myEntries = dbDao.getAllMyEntries(clazzName, keySet); + // get a map of the objects indexed by id + + if (logger.isDebugEnabled()) { + logger.debug("dbAudit: Second comparison; traversing iaeList, size=" + iaeList.size()); + } + for (IntegrityAuditEntity iae : iaeList) { + if (iae.getId() == myIae.getId()) { + if (logger.isDebugEnabled()) { + logger.debug("dbAudit: Second comparison; My Id=" + iae.getId() + ", resourceName=" + + iae.getResourceName()); + } + continue; // no need to compare with self + } else { + if (logger.isDebugEnabled()) { + logger.debug("dbAudit: Second comparison; Id=" + iae.getId() + ", resourceName=" + + iae.getResourceName()); + } + } + // Create properties for the other db node + Properties theirProperties = new Properties(); + theirProperties.put(IntegrityAuditProperties.DB_DRIVER, iae.getJdbcDriver()); + theirProperties.put(IntegrityAuditProperties.DB_URL, iae.getJdbcUrl()); + theirProperties.put(IntegrityAuditProperties.DB_USER, iae.getJdbcUser()); + theirProperties.put(IntegrityAuditProperties.DB_PWD, iae.getJdbcPassword()); + theirProperties.put(IntegrityAuditProperties.SITE_NAME, iae.getSite()); + theirProperties.put(IntegrityAuditProperties.NODE_TYPE, iae.getNodeType()); + + // get a map of the instances for their iae indexed by id + Map<Object, Object> theirEntries = + dbDao.getAllEntries(persistenceUnit, theirProperties, clazzName, keySet); + + /* + * Compare myEntries with theirEntries and get back a set of mismatched IDs. Collect + * the IDs for the class where a mismatch occurred. We will now write an error log + * for each. + */ + Set<Object> misMatchedKeySet = compareEntries(myEntries, theirEntries); + if (!misMatchedKeySet.isEmpty()) { + String keysString = ""; + for (Object key : misMatchedKeySet) { + keysString = keysString.concat(key.toString() + ", "); + errorCount++; + } + writeAuditSummaryLog(clazzName, resourceName, iae.getResourceName(), keysString); + if (logger.isDebugEnabled()) { + for (Object key : misMatchedKeySet) { + writeAuditDebugLog(clazzName, resourceName, iae.getResourceName(), myEntries.get(key), + theirEntries.get(key)); + } + } + } + } + // Time check + if ((System.currentTimeMillis() - startTime) >= dbAuditUpdateMillis) { + // update the timestamp + dbDao.setLastUpdated(); + // reset the startTime + startTime = System.currentTimeMillis(); + } else { + // sleep a couple seconds to break up the activity + if (logger.isDebugEnabled()) { + logger.debug("dbAudit: Second comparison; sleeping " + dbAuditSleepMillis + "ms"); + } + sleep(); + if (logger.isDebugEnabled()) { + logger.debug("dbAudit: Second comparison; waking from sleep"); + } + } + } // end: for(String clazzName: classNameList) + + if (errorCount != 0) { + String msg = " DB Audit: " + errorCount + + " errors found. A large number of errors may indicate DB replication has stopped"; + logger.error(MessageCodes.ERROR_AUDIT, msg); + } + + if (logger.isDebugEnabled()) { + logger.debug("dbAudit: Exiting"); + } + + return; // all done + } + + /** + * Sleeps a bit. + * + * @throws IntegrityAuditException if interrupted + */ + private void sleep() throws IntegrityAuditException { + try { + Thread.sleep(dbAuditSleepMillis); + + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new IntegrityAuditException(e); + } + } + + /** + * dbAuditSimulate simulates the DB audit. + * + * @param resourceName the resouce name + * @param persistenceUnit the persistence unit + * @param simulationIterations the simulations iterations + * @param simulationIntervalMs the simulation interval in milliseconds + * @throws DbAuditException if an error occurs + */ + public void dbAuditSimulate(String resourceName, String persistenceUnit, long simulationIterations, + long simulationIntervalMs) throws DbAuditException { + + try { + logger.info("dbAuditSimulate: Starting audit simulation for resourceName=" + resourceName + + ", persistenceUnit=" + persistenceUnit); + + for (int i = 0; i < simulationIterations; i++) { + dbDao.setLastUpdated(); + logger.info("dbAuditSimulate: i=" + i + ", sleeping " + simulationIntervalMs + "ms"); + Thread.sleep(simulationIntervalMs); + } + + logger.info("dbAuditSimulate: Finished audit simulation for resourceName=" + resourceName + + ", persistenceUnit=" + persistenceUnit); + + } catch (DbDaoTransactionException e) { + throw new DbAuditException(e); + + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new DbAuditException(e); + } + } + + /** + * compareEntries() will compare the lists of entries from the DB. + * + * @param myEntries the entries + * @param theirEntries the entries to compare against myEntries + * @return the set of differences + */ + public Set<Object> compareEntries(Map<Object, Object> myEntries, Map<Object, Object> theirEntries) { + /* + * Compare the entries for the same key in each of the hashmaps. The comparison will be done + * by serializing the objects (create a byte array) and then do a byte array comparison. The + * audit will walk the local repository hash map comparing to the remote cluster hashmap and + * then turn it around and walk the remote hashmap and look for any entries that are not + * present in the local cluster hashmap. + * + * If the objects are not identical, the audit will put the object IDs on a list to try + * after completing the audit of the table it is currently working on. + * + */ + HashSet<Object> misMatchedKeySet = new HashSet<>(); + for (Entry<Object, Object> ent : myEntries.entrySet()) { + Object key = ent.getKey(); + byte[] mySerializedEntry = SerializationUtils.serialize((Serializable) ent.getValue()); + byte[] theirSerializedEntry = SerializationUtils.serialize((Serializable) theirEntries.get(key)); + if (!Arrays.equals(mySerializedEntry, theirSerializedEntry)) { + logger.debug("compareEntries: For myEntries.key=" + key + ", entries do not match"); + misMatchedKeySet.add(key); + } else { + logger.debug("compareEntries: For myEntries.key=" + key + ", entries match"); + } + } + // now compare it in the other direction to catch entries in their set that is not in my set + for (Entry<Object, Object> ent : theirEntries.entrySet()) { + Object key = ent.getKey(); + byte[] mySerializedEntry = SerializationUtils.serialize((Serializable) myEntries.get(key)); + byte[] theirSerializedEntry = SerializationUtils.serialize((Serializable) ent.getValue()); + if (!Arrays.equals(mySerializedEntry, theirSerializedEntry)) { + logger.debug("compareEntries: For theirEntries.key=" + key + ", entries do not match"); + misMatchedKeySet.add(key); + } else { + logger.debug("compareEntries: For theirEntries.key=" + key + ", entries match"); + } + } + + // return a Set of the object IDs + logger.debug("compareEntries: misMatchedKeySet.size()=" + misMatchedKeySet.size()); + return misMatchedKeySet; + } + + /** + * writeAuditDebugLog() writes the mismatched entry details to the debug log. + * + * @param clazzName the class name + * @param resourceName1 resource name 1 + * @param resourceName2 resource name 2 + * @param entry1 entry 1 + * @param entry2 entry 2 + * @throws IntegrityAuditException if the given class cannot be found + */ + public void writeAuditDebugLog(String clazzName, String resourceName1, String resourceName2, Object entry1, + Object entry2) throws IntegrityAuditException { + try { + Class<?> entityClass = Class.forName(clazzName); + String tableName = entityClass.getAnnotation(Table.class).name(); + String msg = "\nDB Audit Error: " + "\n Table Name: " + tableName + + "\n Entry 1 (short prefix style): " + resourceName1 + ": " + + new ReflectionToStringBuilder(entry1, ToStringStyle.SHORT_PREFIX_STYLE).toString() + + "\n Entry 2 (short prefix style): " + resourceName2 + ": " + + new ReflectionToStringBuilder(entry2, ToStringStyle.SHORT_PREFIX_STYLE).toString() + + "\n Entry 1 (recursive style): " + resourceName1 + ": " + + new ReflectionToStringBuilder(entry1, new RecursiveToStringStyle()).toString() + + "\n Entry 2 (recursive style): " + resourceName2 + ": " + + new ReflectionToStringBuilder(entry2, new RecursiveToStringStyle()).toString(); + logger.debug(msg); + + } catch (ClassNotFoundException e) { + throw new IntegrityAuditException(e); + } + + } + + /** + * writeAuditSummaryLog() writes a summary of the DB mismatches to the error log. + * + * @param clazzName the name of the class + * @param resourceName1 resource name 1 + * @param resourceName2 resource name 2 + * @param keys the mismatched entry keys + * @throws IntegrityAuditException if the given class cannot be found + */ + public void writeAuditSummaryLog(String clazzName, String resourceName1, String resourceName2, String keys) + throws IntegrityAuditException { + try { + Class<?> entityClass = Class.forName(clazzName); + String tableName = entityClass.getAnnotation(Table.class).name(); + String msg = " DB Audit Error: Table Name: " + tableName + "; Mismatch between nodes: " + resourceName1 + + " and " + resourceName2 + "; Mismatched entries (keys): " + keys; + logger.info(msg); + } catch (ClassNotFoundException e) { + throw new IntegrityAuditException(e); + } + } + + /** + * Gets the audit-update time. + * + * @return the audit-update time, in milliseconds + */ + protected static long getDbAuditUpdateMillis() { + return dbAuditUpdateMillis; + } + + /** + * Sets the audit-update time. + * + * @param dbAuditUpdateMillis the new audit update time, in milliseconds + */ + protected static void setDbAuditUpdateMillis(long dbAuditUpdateMillis) { + DbAudit.dbAuditUpdateMillis = dbAuditUpdateMillis; + } + + /** + * Gets the audit-sleep time. + * + * @return the audit-sleep time, in milliseconds + */ + protected static long getDbAuditSleepMillis() { + return dbAuditSleepMillis; + } + + /** + * Sets the audit-sleep time. + * + * @param dbAuditSleepMillis the new audit sleep time, in milliseconds + */ + protected static void setDbAuditSleepMillis(long dbAuditSleepMillis) { + DbAudit.dbAuditSleepMillis = dbAuditSleepMillis; + } } diff --git a/integrity-audit/src/main/java/org/onap/policy/common/ia/DbAuditException.java b/integrity-audit/src/main/java/org/onap/policy/common/ia/DbAuditException.java index dc629c65..a539f6bd 100644 --- a/integrity-audit/src/main/java/org/onap/policy/common/ia/DbAuditException.java +++ b/integrity-audit/src/main/java/org/onap/policy/common/ia/DbAuditException.java @@ -21,18 +21,21 @@ package org.onap.policy.common.ia; public class DbAuditException extends IntegrityAuditException { - private static final long serialVersionUID = 1L; - public DbAuditException() { - super(); - } - public DbAuditException(String message) { - super(message); - } + private static final long serialVersionUID = 1L; - public DbAuditException(Throwable cause) { - super(cause); - } - public DbAuditException(String message, Throwable cause) { - super(message, cause); - } + public DbAuditException() { + super(); + } + + public DbAuditException(String message) { + super(message); + } + + public DbAuditException(Throwable cause) { + super(cause); + } + + public DbAuditException(String message, Throwable cause) { + super(message, cause); + } } diff --git a/integrity-audit/src/main/java/org/onap/policy/common/ia/DbDAO.java b/integrity-audit/src/main/java/org/onap/policy/common/ia/DbDAO.java index 73beda78..864adacb 100644 --- a/integrity-audit/src/main/java/org/onap/policy/common/ia/DbDAO.java +++ b/integrity-audit/src/main/java/org/onap/policy/common/ia/DbDAO.java @@ -42,9 +42,8 @@ import javax.persistence.criteria.Root; import javax.persistence.metamodel.ManagedType; import javax.persistence.metamodel.Metamodel; - import org.onap.policy.common.ia.jpa.IntegrityAuditEntity; -import org.onap.policy.common.logging.flexlogger.FlexLogger; +import org.onap.policy.common.logging.flexlogger.FlexLogger; import org.onap.policy.common.logging.flexlogger.Logger; /** @@ -52,703 +51,718 @@ import org.onap.policy.common.logging.flexlogger.Logger; * */ public class DbDAO { - private static final Logger logger = FlexLogger.getLogger(DbDAO.class.getName()); - private String resourceName; - private String persistenceUnit; - private String dbDriver; - private String dbUrl; - private String dbUser; - private String siteName; - private String nodeType; - private Properties properties=null; - - private EntityManagerFactory emf; - - /* - * Supports designation serialization. - */ + private static final Logger logger = FlexLogger.getLogger(DbDAO.class.getName()); + private String resourceName; + private String persistenceUnit; + private String dbDriver; + private String dbUrl; + private String dbUser; + private String siteName; + private String nodeType; + private Properties properties = null; + + private EntityManagerFactory emf; + + /* + * Supports designation serialization. + */ private static final Object lock = new Object(); - /** - * DbDAO Constructor - * - * @param resourceName - * @param persistenceUnit - * @param properties - * @throws IntegrityAuditException - */ - public DbDAO(String resourceName, String persistenceUnit, Properties properties) throws IntegrityAuditException { - this(resourceName, persistenceUnit, properties, null); - } - - /** - * DbDAO Constructor - * - * @param resourceName - * @param persistenceUnit - * @param properties - * @param lastUpdateDate may be {@code null} - * @param altDbUrl may be {@code null} - * @throws IntegrityAuditException - */ - protected DbDAO(String resourceName, String persistenceUnit, Properties properties, String altDbUrl) - throws IntegrityAuditException { - logger.debug("DbDAO contructor: enter"); - - validateProperties(resourceName, persistenceUnit, properties); - - emf = Persistence.createEntityManagerFactory(persistenceUnit, properties); - - register(altDbUrl); - - logger.debug("DbDAO contructor: exit"); - } - - /** - * Release resources (i.e., the EntityManagerFactory). - */ - public void destroy() { - emf.close(); - } - - /** - * validateProperties will validate the properties - * @param resourceName - * @param persistenceUnit - * @param properties - * @throws IntegrityAuditPropertiesException - */ - private void validateProperties(String resourceName, String persistenceUnit, Properties properties) throws IntegrityAuditPropertiesException{ - StringBuilder badparams= new StringBuilder(); - if(IntegrityAudit.parmsAreBad(resourceName, persistenceUnit, properties, badparams)){ - String msg = "DbDAO: Bad parameters: badparams" + badparams; - throw new IntegrityAuditPropertiesException(msg); - } - this.resourceName = resourceName; - this.persistenceUnit = persistenceUnit; - this.dbDriver = properties.getProperty(IntegrityAuditProperties.DB_DRIVER).trim(); - this.dbUrl = properties.getProperty(IntegrityAuditProperties.DB_URL).trim(); - this.dbUser = properties.getProperty(IntegrityAuditProperties.DB_USER).trim(); - this.siteName = properties.getProperty(IntegrityAuditProperties.SITE_NAME).trim(); - this.nodeType = properties.getProperty(IntegrityAuditProperties.NODE_TYPE).trim(); - this.properties = properties; - logger.debug("DbDAO.assignProperties: exit:" - + "\nresourceName: " + this.resourceName - + "\npersistenceUnit: " + this.persistenceUnit - + "\nproperties: " + this.properties); - } - - /** - * getAllMyEntries gets all the DB entries for a particular class - * @param className - * @return - */ - public Map<Object, Object> getAllMyEntries(String className) { - logger.debug("getAllMyEntries: Entering, className=" - + className); - HashMap<Object, Object> resultMap = new HashMap<>(); - EntityManager em = emf.createEntityManager(); - try{ - CriteriaBuilder cb = em.getCriteriaBuilder(); - CriteriaQuery<Object> cq = cb.createQuery(); - Root<?> rootEntry = cq.from(Class.forName(className)); - CriteriaQuery<Object> all = cq.select(rootEntry); - TypedQuery<Object> allQuery = em.createQuery(all); - List<Object> objectList = allQuery.getResultList(); - //Now create the map - - PersistenceUnitUtil util = emf.getPersistenceUnitUtil(); - for (Object o: objectList){ - Object key = util.getIdentifier(o); - resultMap.put(key, o); - } - }catch(Exception e){ - logger.error("getAllEntries encountered exception: ", e); - } - em.close(); - logger.debug("getAllMyEntries: Exit, resultMap.keySet()=" + resultMap.keySet()); - return resultMap; - } - - /** - * getAllMyEntries gets all entries for a class - * @param className - * @param keySet - * @return - */ - public Map<Object, Object> getAllMyEntries(String className, Set<Object> keySet){ - logger.debug("getAllMyEntries: Entering, className=" - + className + ",\n keySet=" + keySet); - - HashMap<Object, Object> resultMap = new HashMap<>(); - EntityManager em = emf.createEntityManager(); - try{ - Class<?> clazz = Class.forName(className); - for(Object key : keySet){ - Object entry = em.find(clazz, key); - resultMap.put(key, entry); - } - }catch(Exception e){ - logger.error("getAllMyEntries encountered exception: ", e); - } - em.close(); - - logger.debug("getAllMyEntries: Returning resultMap, size=" + resultMap.size()); - return resultMap; - } - - /** - * getAllEntries gets all entriesfor a particular persistence unit adn className - * @param persistenceUnit - * @param properties - * @param className - * @return - */ - public Map<Object,Object> getAllEntries(String persistenceUnit, Properties properties, String className){ - - logger.debug("getAllEntries: Entering, persistenceUnit=" - + persistenceUnit + ",\n className=" + className); - HashMap<Object, Object> resultMap = new HashMap<>(); - - EntityManagerFactory theEmf = Persistence.createEntityManagerFactory(persistenceUnit, properties); - EntityManager em = theEmf.createEntityManager(); - try{ - CriteriaBuilder cb = em.getCriteriaBuilder(); - CriteriaQuery<Object> cq = cb.createQuery(); - Root<?> rootEntry = cq.from(Class.forName(className)); - CriteriaQuery<Object> all = cq.select(rootEntry); - TypedQuery<Object> allQuery = em.createQuery(all); - List<Object> objectList = allQuery.getResultList(); - - PersistenceUnitUtil util = theEmf.getPersistenceUnitUtil(); - for (Object o: objectList){ - Object key = util.getIdentifier(o); - resultMap.put(key, o); - } - }catch(Exception e){ - logger.error("getAllEntries encountered exception:", e); - } - em.close(); - theEmf.close(); - - logger.debug("getAllEntries: Returning resultMap, size=" + resultMap.size()); - - return resultMap; - } - - - /** - * getAllEntries gest all entries for a persistence unit - * @param persistenceUnit - * @param properties - * @param className - * @param keySet - * @return - */ - - public Map<Object,Object> getAllEntries(String persistenceUnit, Properties properties, String className, Set<Object> keySet){ - logger.debug("getAllEntries: Entering, persistenceUnit=" - + persistenceUnit + ",\n properties= " + properties + ",\n className=" + className + ",\n keySet= " + keySet); - EntityManagerFactory theEmf = Persistence.createEntityManagerFactory(persistenceUnit, properties); - EntityManager em = theEmf.createEntityManager(); - HashMap<Object, Object> resultMap = new HashMap<>(); - try{ - Class<?> clazz = Class.forName(className); - for(Object key : keySet){ - Object entry = em.find(clazz, key); - resultMap.put(key, entry); - } - }catch(Exception e){ - String msg = "getAllEntries encountered exception: " + e; - logger.error(msg, e); - } - em.close(); - theEmf.close(); - logger.debug("getAllEntries: Exit, resultMap, size=" + resultMap.size()); - return resultMap; - } - - /** - * getIntegrityAuditEntities() Get all the IntegrityAuditEntities for a particular persistence unit - * and node type - * @param persistenceUnit - * @param nodeType - * @return - * @throws DbDaoTransactionException - */ - @SuppressWarnings("unchecked") - public List<IntegrityAuditEntity> getIntegrityAuditEntities(String persistenceUnit, String nodeType) throws DbDaoTransactionException { - logger.debug("getIntegrityAuditEntities: Entering, persistenceUnit=" - + persistenceUnit + ",\n nodeType= " + nodeType); - try{ - EntityManager em = emf.createEntityManager(); - // Start a transaction - EntityTransaction et = em.getTransaction(); - - et.begin(); - - // if IntegrityAuditEntity entry exists for resourceName and PU, update it. If not found, create a new entry - Query iaequery = em.createQuery("Select i from IntegrityAuditEntity i where i.persistenceUnit=:pu and i.nodeType=:nt"); - iaequery.setParameter("pu", persistenceUnit); - iaequery.setParameter("nt", nodeType); - - List<IntegrityAuditEntity> iaeList = iaequery.getResultList(); - - // commit transaction - et.commit(); - em.close(); - logger.debug("getIntegrityAuditEntities: Exit, iaeList=" + iaeList); - return iaeList; - }catch (Exception e){ - String msg = "DbDAO: " + "getIntegrityAuditEntities() " + "ecountered a problem in execution: "; - logger.error(msg, e); - throw new DbDaoTransactionException(e); - } - - } - - /** - * getMyIntegrityAuditEntity() gets my IntegrityAuditEntity - * @return - * @throws DbDaoTransactionException - */ - public IntegrityAuditEntity getMyIntegrityAuditEntity() throws DbDaoTransactionException{ - try{ - EntityManager em = emf.createEntityManager(); - - // Start a transaction - EntityTransaction et = em.getTransaction(); - - et.begin(); - - // if IntegrityAuditEntity entry exists for resourceName and PU, retrieve it - Query iaequery = em.createQuery("Select i from IntegrityAuditEntity i where i.resourceName=:rn and i.persistenceUnit=:pu"); - iaequery.setParameter("rn", this.resourceName); - iaequery.setParameter("pu", this.persistenceUnit); - - @SuppressWarnings("rawtypes") - List iaeList = iaequery.getResultList(); - IntegrityAuditEntity iae = null; - - if(!iaeList.isEmpty()){ - //ignores multiple results - iae = (IntegrityAuditEntity) iaeList.get(0); - // refresh the object from DB in case cached data was returned - em.refresh(iae); - logger.info("Resource: " + this.resourceName + " with PersistenceUnit: " + this.persistenceUnit - + " exists"); - }else{ - // If it does not exist, log an error - logger.error("Attempting to setLastUpdated" - + " on an entry that does not exist:" - +" resource " + this.resourceName + " with PersistenceUnit: " + this.persistenceUnit); - } - - // close the transaction - et.commit(); - // close the EntityManager - em.close(); - - return iae; - }catch (Exception e){ - String msg = "DbDAO: " + "setLastUpdated() " + "ecountered a problem in execution: "; - logger.error(msg + e); - throw new DbDaoTransactionException(e); - } - } - - - /** - * getIntegrityAuditEntity() gets the IntegrityAuditEntity with a particular ID - * @param id - * @return - * @throws DbDaoTransactionException - */ - public IntegrityAuditEntity getIntegrityAuditEntity(long id) throws DbDaoTransactionException{ - try{ - EntityManager em = emf.createEntityManager(); - - // Start a transaction - EntityTransaction et = em.getTransaction(); - - et.begin(); - - IntegrityAuditEntity iae = em.find(IntegrityAuditEntity.class, id); - - et.commit(); - em.close(); - - return iae; - }catch (Exception e){ - String msg = "DbDAO: " + "getIntegrityAuditEntity() " + "ecountered a problem in execution: "; - logger.error(msg + e); - throw new DbDaoTransactionException(e); - } - } - - /** - * getPersistenceClassNames() gets all the persistence class names. - * @return - */ - public Set<String> getPersistenceClassNames(){ - logger.debug("DbDAO: getPersistenceClassNames() entry"); - HashSet<String> returnList = new HashSet<>(); - final Metamodel mm = emf.getMetamodel(); - logger.debug("\n" + persistenceUnit +" persistence unit classes:"); - for (final ManagedType<?> managedType : mm.getManagedTypes()) { - Class<?> c = managedType.getJavaType(); - logger.debug(" " + c.getSimpleName()); - returnList.add(c.getName()); //the full class name needed to make a query using jpa - } - logger.debug("DbDAO: getPersistenceClassNames() exit"); - return returnList; - } - - /** - * Register the IntegrityAudit instance - * @param altDbUrl alternate DB URL to be placed into the record, - * or {@code null} to use the default - */ - private void register(String altDbUrl) throws DbDaoTransactionException { - try{ - EntityManager em = emf.createEntityManager(); - - // Start a transaction - EntityTransaction et = em.getTransaction(); - - et.begin(); - - // if IntegrityAuditEntity entry exists for resourceName and PU, update it. If not found, create a new entry - Query iaequery = em.createQuery("Select i from IntegrityAuditEntity i where i.resourceName=:rn and i.persistenceUnit=:pu"); - iaequery.setParameter("rn", this.resourceName); - iaequery.setParameter("pu", this.persistenceUnit); - - @SuppressWarnings("rawtypes") - List iaeList = iaequery.getResultList(); - IntegrityAuditEntity iae; - - //If it already exists, we just want to update the properties and lastUpdated date - if(!iaeList.isEmpty()){ - //ignores multiple results - iae = (IntegrityAuditEntity) iaeList.get(0); - // refresh the object from DB in case cached data was returned - em.refresh(iae); - logger.info("Resource: " + this.resourceName + " with PersistenceUnit: " + this.persistenceUnit - + " exists and entry be updated"); - }else{ - // If it does not exist, we also must add teh resourceName, persistenceUnit and designated values - logger.info("Adding resource " + resourceName + " with PersistenceUnit: " + this.persistenceUnit - + " to IntegrityAuditEntity table"); - iae = new IntegrityAuditEntity(); - iae.setResourceName(this.resourceName); - iae.setPersistenceUnit(this.persistenceUnit); - iae.setDesignated(false); - } - //update/set properties in entry - iae.setSite(this.siteName); - iae.setNodeType(this.nodeType); - iae.setJdbcDriver(this.dbDriver); - iae.setJdbcPassword(properties.getProperty(IntegrityAuditProperties.DB_PWD).trim()); - iae.setJdbcUrl(altDbUrl == null ? this.dbUrl : altDbUrl); - iae.setJdbcUser(dbUser); - - em.persist(iae); - // flush to the DB - em.flush(); - - // commit transaction - et.commit(); - em.close(); - }catch (Exception e){ - String msg = "DbDAO: " + "register() " + "encountered a problem in execution: "; - logger.error(msg + e); - throw new DbDaoTransactionException(e); - } - - } - - public void setDesignated(boolean designated) throws DbDaoTransactionException{ - setDesignated(this.resourceName, this.persistenceUnit, designated); - } - - - public void setDesignated(String rName, String pUnit, boolean desig) throws DbDaoTransactionException{ - logger.debug("setDesignated: enter, resourceName: " + rName + ", persistenceUnit: " - + pUnit + ", designated: " + desig); - try{ - - EntityManager em = emf.createEntityManager(); - - // Start a transaction - EntityTransaction et = em.getTransaction(); - - et.begin(); - - // if IntegrityAuditEntity entry exists for resourceName and PU, update it. If not found, create a new entry - Query iaequery = em.createQuery("Select i from IntegrityAuditEntity i where i.resourceName=:rn and i.persistenceUnit=:pu"); - iaequery.setParameter("rn", rName); - iaequery.setParameter("pu", pUnit); - - @SuppressWarnings("rawtypes") - List iaeList = iaequery.getResultList(); - IntegrityAuditEntity iae; - - if(!iaeList.isEmpty()){ - //ignores multiple results - iae = (IntegrityAuditEntity) iaeList.get(0); - // refresh the object from DB in case cached data was returned - em.refresh(iae); - logger.info("Resource: " + rName + " with PersistenceUnit: " + pUnit - + " exists and designated be updated"); - iae.setDesignated(desig); - - em.persist(iae); - // flush to the DB - em.flush(); - }else{ - // If it does not exist, log an error - logger.error("Attempting to setDesignated(" - + desig + ") on an entry that does not exist:" - +" resource " + rName + " with PersistenceUnit: " + pUnit); - } - - // close the transaction - et.commit(); - // close the EntityManager - em.close(); - }catch (Exception e){ - String msg = "DbDAO: " + "setDesignated() " + "ecountered a problem in execution: "; - logger.error(msg + e); - throw new DbDaoTransactionException(e); - } - - } - - public void setLastUpdated() throws DbDaoTransactionException{ - logger.debug("setLastUpdated: enter, resourceName: " + this.resourceName + ", persistenceUnit: " - + this.persistenceUnit); - try{ - EntityManager em = emf.createEntityManager(); - - // Start a transaction - EntityTransaction et = em.getTransaction(); - - et.begin(); - - // if IntegrityAuditEntity entry exists for resourceName and PU, update it. If not found, create a new entry - Query iaequery = em.createQuery("Select i from IntegrityAuditEntity i where i.resourceName=:rn and i.persistenceUnit=:pu"); - iaequery.setParameter("rn", this.resourceName); - iaequery.setParameter("pu", this.persistenceUnit); - - @SuppressWarnings("rawtypes") - List iaeList = iaequery.getResultList(); - IntegrityAuditEntity iae; - - if(!iaeList.isEmpty()){ - //ignores multiple results - iae = (IntegrityAuditEntity) iaeList.get(0); - // refresh the object from DB in case cached data was returned - em.refresh(iae); - logger.info("Resource: " + this.resourceName + " with PersistenceUnit: " + this.persistenceUnit - + " exists and lastUpdated be updated"); - iae.setLastUpdated(new Date()); - - em.persist(iae); - // flush to the DB - em.flush(); - }else{ - // If it does not exist, log an error - logger.error("Attempting to setLastUpdated" - + " on an entry that does not exist:" - +" resource " + this.resourceName + " with PersistenceUnit: " + this.persistenceUnit); - } - - // close the transaction - et.commit(); - // close the EntityManager - em.close(); - }catch (Exception e){ - String msg = "DbDAO: " + "setLastUpdated() " + "ecountered a problem in execution: "; - logger.error(msg + e); - throw new DbDaoTransactionException(e); - } - - } - - /** - * Normally this method should only be used in a JUnit test environment. - * Manually deletes all PDP records in droolspdpentity table. - */ - public int deleteAllIntegrityAuditEntities() throws DbDaoTransactionException { - - try{ - - if (!IntegrityAudit.isUnitTesting()) { - String msg = "DbDAO: " + "deleteAllIntegrityAuditEntities() " + "should only be invoked during JUnit testing"; - logger.error(msg); - throw new DbDaoTransactionException(msg); - } - - EntityManager em = emf.createEntityManager(); - // Start a transaction - EntityTransaction et = em.getTransaction(); - - et.begin(); - - // if IntegrityAuditEntity entry exists for resourceName and PU, update it. If not found, create a new entry - Query iaequery = em.createQuery("Delete from IntegrityAuditEntity"); - - int returnCode = iaequery.executeUpdate(); - - // commit transaction - et.commit(); - em.close(); - - logger.info("deleteAllIntegrityAuditEntities: returnCode=" + returnCode); - - return returnCode; - - }catch (Exception e){ - String msg = "DbDAO: " + "deleteAllIntegrityAuditEntities() " + "encountered a problem in execution: "; - logger.error(msg + e); - throw new DbDaoTransactionException(e); - } - - } - - /** - * Changes designation to specified resourceName - * - * static lock object in conjunction with synchronized keyword ensures that - * designation changes are done serially within a resource. I.e. static lock - * ensures that multiple instantiations of DbDAO don't interleave - * changeDesignated() invocations and potentially produce simultaneous - * designations. - * - * Optimistic locking (the default, versus pessimistic) is sufficient to - * avoid simultaneous designations from interleaved changeDesignated() - * invocations from different resources (entities), because it prevents - * "dirty" and "non-repeatable" reads. - * - * See http://www.objectdb.com/api/java/jpa/LockModeType - * - * and - * - * http://stackoverflow.com/questions/2120248/how-to-synchronize-a-static- - * variable-among-threads-running-different-instances-o - */ - public void changeDesignated(String resourceName, String persistenceUnit, - String nodeType) throws DbDaoTransactionException { - - if (logger.isDebugEnabled()) { - logger.debug("changeDesignated: Entering, resourceName=" - + resourceName + ", persistenceUnit=" + persistenceUnit - + ", nodeType=" + nodeType); - } - - long startTime = System.currentTimeMillis(); - - synchronized (lock) { - - EntityManager em = null; - try { - - em = emf.createEntityManager(); - em.getTransaction().begin(); - - /* - * Define query - */ - Query query = em - .createQuery("Select i from IntegrityAuditEntity i where i.persistenceUnit=:pu and i.nodeType=:nt"); - query.setParameter("pu", persistenceUnit); - query.setParameter("nt", nodeType); - - /* - * Execute query using pessimistic write lock. This ensures that if anyone else is currently reading - * the records we'll throw a LockTimeoutException. - */ - @SuppressWarnings("unchecked") - List<IntegrityAuditEntity> integrityAuditEntityList = (List<IntegrityAuditEntity>) query - .getResultList(); - for (Object o : integrityAuditEntityList) { - if (o instanceof IntegrityAuditEntity) { - IntegrityAuditEntity integrityAuditEntity = (IntegrityAuditEntity) o; - if (integrityAuditEntity.getResourceName().equals( - resourceName)) { - if (logger.isDebugEnabled()) { - logger.debug("changeDesignated: Designating resourceName=" - + integrityAuditEntity - .getResourceName()); - } - integrityAuditEntity.setDesignated(true); - } else { - if (logger.isDebugEnabled()) { - logger.debug("changeDesignated: Removing designation from resourceName=" - + integrityAuditEntity - .getResourceName()); - } - integrityAuditEntity.setDesignated(false); - } - } - } - - if (logger.isDebugEnabled()) { - logger.debug("changeDesignated: Committing designation to resourceName=" - + resourceName); - } - em.getTransaction().commit(); - - /* - * If we get a LockTimeoutException, no harm done really. We'll - * probably be successful on the next attempt. The odds of - * another DbDAO instance on this entity or another entity - * attempting a simultaneous IntegrityAuditEntity table - * read/update are pretty slim (we're only in this method for - * two or three milliseconds) - */ - } catch (LockTimeoutException e) { - if (em != null) { - em.getTransaction().rollback(); - - String msg = "DbDAO: " + "changeDesignated() " - + "caught LockTimeoutException, message=" + e.getMessage(); - logger.error(msg + e); - throw new DbDaoTransactionException(msg, e); - } - else { - String msg = "DbDAO: " + "changeDesignated() " - + "caught LockTimeoutException, message=" + e.getMessage() - + ". Error rolling back transaction."; - logger.error(msg + e); - throw new DbDaoTransactionException(msg, e); - } - } catch (Exception e) { - if (em != null) { - em.getTransaction().rollback(); - - String msg = "DbDAO: " + "changeDesignated() " - + "caught Exception, message=" + e.getMessage(); - logger.error(msg + e); - throw new DbDaoTransactionException(msg, e); - } - else { - String msg = "DbDAO: " + "changeDesignated() " - + "caught LockTimeoutException, message=" + e.getMessage() - + ". Error rolling back transaction."; - logger.error(msg + e); - throw new DbDaoTransactionException(msg, e); - } - } - - } // end synchronized block - - if (logger.isDebugEnabled()) { - logger.debug("changeDesignated: Exiting; time expended=" - + (System.currentTimeMillis() - startTime) + "ms"); - } - - } + /** + * DbDAO Constructor. + * + * @param resourceName the resource name + * @param persistenceUnit the persistence unit + * @param properties the properties + * @throws IntegrityAuditException if an error occurs + */ + public DbDAO(String resourceName, String persistenceUnit, Properties properties) throws IntegrityAuditException { + this(resourceName, persistenceUnit, properties, null); + } + + /** + * DbDAO Constructor. + * + * @param resourceName the resource name + * @param persistenceUnit the persistence unit + * @param properties the properties + * @param lastUpdateDate may be {@code null} + * @param altDbUrl may be {@code null} + * @throws IntegrityAuditException if an error occurs + */ + protected DbDAO(String resourceName, String persistenceUnit, Properties properties, String altDbUrl) + throws IntegrityAuditException { + logger.debug("DbDAO contructor: enter"); + + validateProperties(resourceName, persistenceUnit, properties); + + emf = Persistence.createEntityManagerFactory(persistenceUnit, properties); + + register(altDbUrl); + + logger.debug("DbDAO contructor: exit"); + } + + /** + * Release resources (i.e., the EntityManagerFactory). + */ + public void destroy() { + emf.close(); + } + + /** + * validateProperties will validate the properties. + * + * @param resourceName the rseource name + * @param persistenceUnit the persistence unit + * @param properties the properties + * @throws IntegrityAuditPropertiesException if an error occurs + */ + private void validateProperties(String resourceName, String persistenceUnit, Properties properties) + throws IntegrityAuditPropertiesException { + StringBuilder badparams = new StringBuilder(); + if (IntegrityAudit.parmsAreBad(resourceName, persistenceUnit, properties, badparams)) { + String msg = "DbDAO: Bad parameters: badparams" + badparams; + throw new IntegrityAuditPropertiesException(msg); + } + this.resourceName = resourceName; + this.persistenceUnit = persistenceUnit; + this.dbDriver = properties.getProperty(IntegrityAuditProperties.DB_DRIVER).trim(); + this.dbUrl = properties.getProperty(IntegrityAuditProperties.DB_URL).trim(); + this.dbUser = properties.getProperty(IntegrityAuditProperties.DB_USER).trim(); + this.siteName = properties.getProperty(IntegrityAuditProperties.SITE_NAME).trim(); + this.nodeType = properties.getProperty(IntegrityAuditProperties.NODE_TYPE).trim(); + this.properties = properties; + logger.debug("DbDAO.assignProperties: exit:" + "\nresourceName: " + this.resourceName + "\npersistenceUnit: " + + this.persistenceUnit + "\nproperties: " + this.properties); + } + + /** + * getAllMyEntries gets all the DB entries for a particular class. + * + * @param className the class name + * @return all the DB entries for the given class + */ + public Map<Object, Object> getAllMyEntries(String className) { + logger.debug("getAllMyEntries: Entering, className=" + className); + HashMap<Object, Object> resultMap = new HashMap<>(); + EntityManager em = emf.createEntityManager(); + try { + CriteriaBuilder cb = em.getCriteriaBuilder(); + CriteriaQuery<Object> cq = cb.createQuery(); + Root<?> rootEntry = cq.from(Class.forName(className)); + CriteriaQuery<Object> all = cq.select(rootEntry); + TypedQuery<Object> allQuery = em.createQuery(all); + List<Object> objectList = allQuery.getResultList(); + // Now create the map + + PersistenceUnitUtil util = emf.getPersistenceUnitUtil(); + for (Object o : objectList) { + Object key = util.getIdentifier(o); + resultMap.put(key, o); + } + } catch (Exception e) { + logger.error("getAllEntries encountered exception: ", e); + } + em.close(); + logger.debug("getAllMyEntries: Exit, resultMap.keySet()=" + resultMap.keySet()); + return resultMap; + } + + /** + * getAllMyEntries gets all entries for a class. + * + * @param className the name of the class + * @param keySet the keys to get the entries for + * @return the map of requested entries + */ + public Map<Object, Object> getAllMyEntries(String className, Set<Object> keySet) { + logger.debug("getAllMyEntries: Entering, className=" + className + ",\n keySet=" + keySet); + + HashMap<Object, Object> resultMap = new HashMap<>(); + EntityManager em = emf.createEntityManager(); + try { + Class<?> clazz = Class.forName(className); + for (Object key : keySet) { + Object entry = em.find(clazz, key); + resultMap.put(key, entry); + } + } catch (Exception e) { + logger.error("getAllMyEntries encountered exception: ", e); + } + em.close(); + + logger.debug("getAllMyEntries: Returning resultMap, size=" + resultMap.size()); + return resultMap; + } + + /** + * getAllEntries gets all entriesfor a particular persistence unit adn className. + * + * @param persistenceUnit the persistence unit + * @param properties the properties + * @param className the class name + * @return the map of entries + */ + public Map<Object, Object> getAllEntries(String persistenceUnit, Properties properties, String className) { + + logger.debug("getAllEntries: Entering, persistenceUnit=" + persistenceUnit + ",\n className=" + className); + HashMap<Object, Object> resultMap = new HashMap<>(); + + EntityManagerFactory theEmf = Persistence.createEntityManagerFactory(persistenceUnit, properties); + EntityManager em = theEmf.createEntityManager(); + try { + CriteriaBuilder cb = em.getCriteriaBuilder(); + CriteriaQuery<Object> cq = cb.createQuery(); + Root<?> rootEntry = cq.from(Class.forName(className)); + CriteriaQuery<Object> all = cq.select(rootEntry); + TypedQuery<Object> allQuery = em.createQuery(all); + List<Object> objectList = allQuery.getResultList(); + + PersistenceUnitUtil util = theEmf.getPersistenceUnitUtil(); + for (Object o : objectList) { + Object key = util.getIdentifier(o); + resultMap.put(key, o); + } + } catch (Exception e) { + logger.error("getAllEntries encountered exception:", e); + } + em.close(); + theEmf.close(); + + logger.debug("getAllEntries: Returning resultMap, size=" + resultMap.size()); + + return resultMap; + } + + + /** + * getAllEntries gets all entries for a persistence unit. + * + * @param persistenceUnit the persistence unit + * @param properties the properties + * @param className the class name + * @param keySet the keys + * @return the map of entries + */ + + public Map<Object, Object> getAllEntries(String persistenceUnit, Properties properties, String className, + Set<Object> keySet) { + logger.debug("getAllEntries: Entering, persistenceUnit=" + persistenceUnit + ",\n properties= " + properties + + ",\n className=" + className + ",\n keySet= " + keySet); + EntityManagerFactory theEmf = Persistence.createEntityManagerFactory(persistenceUnit, properties); + EntityManager em = theEmf.createEntityManager(); + HashMap<Object, Object> resultMap = new HashMap<>(); + try { + Class<?> clazz = Class.forName(className); + for (Object key : keySet) { + Object entry = em.find(clazz, key); + resultMap.put(key, entry); + } + } catch (Exception e) { + String msg = "getAllEntries encountered exception: " + e; + logger.error(msg, e); + } + em.close(); + theEmf.close(); + logger.debug("getAllEntries: Exit, resultMap, size=" + resultMap.size()); + return resultMap; + } + + /** + * getIntegrityAuditEntities() Get all the IntegrityAuditEntities for a particular persistence + * unit and node type. + * + * @param persistenceUnit the persistence unit + * @param nodeType the node type + * @return the list of IntegrityAuditEntity + * @throws DbDaoTransactionException if an error occurs + */ + @SuppressWarnings("unchecked") + public List<IntegrityAuditEntity> getIntegrityAuditEntities(String persistenceUnit, String nodeType) + throws DbDaoTransactionException { + logger.debug("getIntegrityAuditEntities: Entering, persistenceUnit=" + persistenceUnit + ",\n nodeType= " + + nodeType); + try { + EntityManager em = emf.createEntityManager(); + // Start a transaction + EntityTransaction et = em.getTransaction(); + + et.begin(); + + // if IntegrityAuditEntity entry exists for resourceName and PU, update it. If not + // found, create a new entry + Query iaequery = em + .createQuery("Select i from IntegrityAuditEntity i where i.persistenceUnit=:pu and i.nodeType=:nt"); + iaequery.setParameter("pu", persistenceUnit); + iaequery.setParameter("nt", nodeType); + + List<IntegrityAuditEntity> iaeList = iaequery.getResultList(); + + // commit transaction + et.commit(); + em.close(); + logger.debug("getIntegrityAuditEntities: Exit, iaeList=" + iaeList); + return iaeList; + } catch (Exception e) { + String msg = "DbDAO: " + "getIntegrityAuditEntities() " + "ecountered a problem in execution: "; + logger.error(msg, e); + throw new DbDaoTransactionException(e); + } + + } + + /** + * getMyIntegrityAuditEntity() gets my IntegrityAuditEntity. + * + * @return the IntegrityAuditEntity + * @throws DbDaoTransactionException if an error occurs + */ + public IntegrityAuditEntity getMyIntegrityAuditEntity() throws DbDaoTransactionException { + try { + EntityManager em = emf.createEntityManager(); + + // Start a transaction + EntityTransaction et = em.getTransaction(); + + et.begin(); + + // if IntegrityAuditEntity entry exists for resourceName and PU, retrieve it + Query iaequery = em.createQuery( + "Select i from IntegrityAuditEntity i where i.resourceName=:rn and i.persistenceUnit=:pu"); + iaequery.setParameter("rn", this.resourceName); + iaequery.setParameter("pu", this.persistenceUnit); + + @SuppressWarnings("rawtypes") + List iaeList = iaequery.getResultList(); + IntegrityAuditEntity iae = null; + + if (!iaeList.isEmpty()) { + // ignores multiple results + iae = (IntegrityAuditEntity) iaeList.get(0); + // refresh the object from DB in case cached data was returned + em.refresh(iae); + logger.info("Resource: " + this.resourceName + " with PersistenceUnit: " + this.persistenceUnit + + " exists"); + } else { + // If it does not exist, log an error + logger.error("Attempting to setLastUpdated" + " on an entry that does not exist:" + " resource " + + this.resourceName + " with PersistenceUnit: " + this.persistenceUnit); + } + + // close the transaction + et.commit(); + // close the EntityManager + em.close(); + + return iae; + } catch (Exception e) { + String msg = "DbDAO: " + "setLastUpdated() " + "ecountered a problem in execution: "; + logger.error(msg + e); + throw new DbDaoTransactionException(e); + } + } + + + /** + * getIntegrityAuditEntity() gets the IntegrityAuditEntity with a particular ID. + * + * @param id the ID + * @return the IntegrityAuditEntity + * @throws DbDaoTransactionException if an error occurs + */ + public IntegrityAuditEntity getIntegrityAuditEntity(long id) throws DbDaoTransactionException { + try { + EntityManager em = emf.createEntityManager(); + + // Start a transaction + EntityTransaction et = em.getTransaction(); + + et.begin(); + + IntegrityAuditEntity iae = em.find(IntegrityAuditEntity.class, id); + + et.commit(); + em.close(); + + return iae; + } catch (Exception e) { + String msg = "DbDAO: " + "getIntegrityAuditEntity() " + "ecountered a problem in execution: "; + logger.error(msg + e); + throw new DbDaoTransactionException(e); + } + } + + /** + * getPersistenceClassNames() gets all the persistence class names. + * + * @return the persistence class names + */ + public Set<String> getPersistenceClassNames() { + logger.debug("DbDAO: getPersistenceClassNames() entry"); + HashSet<String> returnList = new HashSet<>(); + final Metamodel mm = emf.getMetamodel(); + logger.debug("\n" + persistenceUnit + " persistence unit classes:"); + for (final ManagedType<?> managedType : mm.getManagedTypes()) { + Class<?> clazz = managedType.getJavaType(); + logger.debug(" " + clazz.getSimpleName()); + returnList.add(clazz.getName()); // the full class name needed to make a query using jpa + } + logger.debug("DbDAO: getPersistenceClassNames() exit"); + return returnList; + } + + /** + * Register the IntegrityAudit instance. + * + * @param altDbUrl alternate DB URL to be placed into the record, or {@code null} to use the + * default + */ + private void register(String altDbUrl) throws DbDaoTransactionException { + try { + EntityManager em = emf.createEntityManager(); + + // Start a transaction + EntityTransaction et = em.getTransaction(); + + et.begin(); + + // if IntegrityAuditEntity entry exists for resourceName and PU, update it. If not + // found, create a new entry + Query iaequery = em.createQuery( + "Select i from IntegrityAuditEntity i where i.resourceName=:rn and i.persistenceUnit=:pu"); + iaequery.setParameter("rn", this.resourceName); + iaequery.setParameter("pu", this.persistenceUnit); + + @SuppressWarnings("rawtypes") + List iaeList = iaequery.getResultList(); + IntegrityAuditEntity iae; + + // If it already exists, we just want to update the properties and lastUpdated date + if (!iaeList.isEmpty()) { + // ignores multiple results + iae = (IntegrityAuditEntity) iaeList.get(0); + // refresh the object from DB in case cached data was returned + em.refresh(iae); + logger.info("Resource: " + this.resourceName + " with PersistenceUnit: " + this.persistenceUnit + + " exists and entry be updated"); + } else { + // If it does not exist, we also must add teh resourceName, persistenceUnit and + // designated values + logger.info("Adding resource " + resourceName + " with PersistenceUnit: " + this.persistenceUnit + + " to IntegrityAuditEntity table"); + iae = new IntegrityAuditEntity(); + iae.setResourceName(this.resourceName); + iae.setPersistenceUnit(this.persistenceUnit); + iae.setDesignated(false); + } + // update/set properties in entry + iae.setSite(this.siteName); + iae.setNodeType(this.nodeType); + iae.setJdbcDriver(this.dbDriver); + iae.setJdbcPassword(properties.getProperty(IntegrityAuditProperties.DB_PWD).trim()); + iae.setJdbcUrl(altDbUrl == null ? this.dbUrl : altDbUrl); + iae.setJdbcUser(dbUser); + + em.persist(iae); + // flush to the DB + em.flush(); + + // commit transaction + et.commit(); + em.close(); + } catch (Exception e) { + String msg = "DbDAO: " + "register() " + "encountered a problem in execution: "; + logger.error(msg + e); + throw new DbDaoTransactionException(e); + } + + } + + public void setDesignated(boolean designated) throws DbDaoTransactionException { + setDesignated(this.resourceName, this.persistenceUnit, designated); + } + + /** + * Set designated. + * + * @param resourceName the resource name + * @param persistenceUnit the persistence unit + * @param desig true if is designated + * @throws DbDaoTransactionException if an error occurs + */ + public void setDesignated(String resourceName, String persistenceUnit, boolean desig) + throws DbDaoTransactionException { + logger.debug("setDesignated: enter, resourceName: " + resourceName + ", persistenceUnit: " + persistenceUnit + + ", designated: " + desig); + try { + + EntityManager em = emf.createEntityManager(); + + // Start a transaction + EntityTransaction et = em.getTransaction(); + + et.begin(); + + // if IntegrityAuditEntity entry exists for resourceName and PU, update it. If not + // found, create a new entry + Query iaequery = em.createQuery( + "Select i from IntegrityAuditEntity i where i.resourceName=:rn and i.persistenceUnit=:pu"); + iaequery.setParameter("rn", resourceName); + iaequery.setParameter("pu", persistenceUnit); + + @SuppressWarnings("rawtypes") + List iaeList = iaequery.getResultList(); + IntegrityAuditEntity iae; + + if (!iaeList.isEmpty()) { + // ignores multiple results + iae = (IntegrityAuditEntity) iaeList.get(0); + // refresh the object from DB in case cached data was returned + em.refresh(iae); + logger.info("Resource: " + resourceName + " with PersistenceUnit: " + persistenceUnit + + " exists and designated be updated"); + iae.setDesignated(desig); + + em.persist(iae); + // flush to the DB + em.flush(); + } else { + // If it does not exist, log an error + logger.error("Attempting to setDesignated(" + desig + ") on an entry that does not exist:" + + " resource " + resourceName + " with PersistenceUnit: " + persistenceUnit); + } + + // close the transaction + et.commit(); + // close the EntityManager + em.close(); + } catch (Exception e) { + String msg = "DbDAO: " + "setDesignated() " + "ecountered a problem in execution: "; + logger.error(msg + e); + throw new DbDaoTransactionException(e); + } + + } + + /** + * Set last updated. + * + * @throws DbDaoTransactionException if an error occurs + */ + public void setLastUpdated() throws DbDaoTransactionException { + logger.debug("setLastUpdated: enter, resourceName: " + this.resourceName + ", persistenceUnit: " + + this.persistenceUnit); + try { + EntityManager em = emf.createEntityManager(); + + // Start a transaction + EntityTransaction et = em.getTransaction(); + + et.begin(); + + // if IntegrityAuditEntity entry exists for resourceName and PU, update it. If not + // found, create a new entry + Query iaequery = em.createQuery( + "Select i from IntegrityAuditEntity i where i.resourceName=:rn and i.persistenceUnit=:pu"); + iaequery.setParameter("rn", this.resourceName); + iaequery.setParameter("pu", this.persistenceUnit); + + @SuppressWarnings("rawtypes") + List iaeList = iaequery.getResultList(); + IntegrityAuditEntity iae; + + if (!iaeList.isEmpty()) { + // ignores multiple results + iae = (IntegrityAuditEntity) iaeList.get(0); + // refresh the object from DB in case cached data was returned + em.refresh(iae); + logger.info("Resource: " + this.resourceName + " with PersistenceUnit: " + this.persistenceUnit + + " exists and lastUpdated be updated"); + iae.setLastUpdated(new Date()); + + em.persist(iae); + // flush to the DB + em.flush(); + } else { + // If it does not exist, log an error + logger.error("Attempting to setLastUpdated" + " on an entry that does not exist:" + " resource " + + this.resourceName + " with PersistenceUnit: " + this.persistenceUnit); + } + + // close the transaction + et.commit(); + // close the EntityManager + em.close(); + } catch (Exception e) { + String msg = "DbDAO: " + "setLastUpdated() " + "ecountered a problem in execution: "; + logger.error(msg + e); + throw new DbDaoTransactionException(e); + } + + } + + /** + * Normally this method should only be used in a JUnit test environment. Manually deletes all + * PDP records in droolspdpentity table. + */ + public int deleteAllIntegrityAuditEntities() throws DbDaoTransactionException { + + try { + + if (!IntegrityAudit.isUnitTesting()) { + String msg = "DbDAO: " + "deleteAllIntegrityAuditEntities() " + + "should only be invoked during JUnit testing"; + logger.error(msg); + throw new DbDaoTransactionException(msg); + } + + EntityManager em = emf.createEntityManager(); + // Start a transaction + EntityTransaction et = em.getTransaction(); + + et.begin(); + + // if IntegrityAuditEntity entry exists for resourceName and PU, update it. If not + // found, create a new entry + Query iaequery = em.createQuery("Delete from IntegrityAuditEntity"); + + int returnCode = iaequery.executeUpdate(); + + // commit transaction + et.commit(); + em.close(); + + logger.info("deleteAllIntegrityAuditEntities: returnCode=" + returnCode); + + return returnCode; + + } catch (Exception e) { + String msg = "DbDAO: " + "deleteAllIntegrityAuditEntities() " + "encountered a problem in execution: "; + logger.error(msg + e); + throw new DbDaoTransactionException(e); + } + + } + + /** + * Changes designation to specified resourceName + * + * <p>static lock object in conjunction with synchronized keyword ensures that designation + * changes are done serially within a resource. I.e. static lock ensures that multiple + * instantiations of DbDAO don't interleave changeDesignated() invocations and potentially + * produce simultaneous designations. + * + * <p>Optimistic locking (the default, versus pessimistic) is sufficient to avoid simultaneous + * designations from interleaved changeDesignated() invocations from different resources + * (entities), because it prevents "dirty" and "non-repeatable" reads. + * + * <p>See http://www.objectdb.com/api/java/jpa/LockModeType + * + * <p>and + * + * <p>http://stackoverflow.com/questions/2120248/how-to-synchronize-a-static- + * variable-among-threads-running-different-instances-o + */ + public void changeDesignated(String resourceName, String persistenceUnit, String nodeType) + throws DbDaoTransactionException { + + if (logger.isDebugEnabled()) { + logger.debug("changeDesignated: Entering, resourceName=" + resourceName + ", persistenceUnit=" + + persistenceUnit + ", nodeType=" + nodeType); + } + + long startTime = System.currentTimeMillis(); + + synchronized (lock) { + + EntityManager em = null; + try { + + em = emf.createEntityManager(); + em.getTransaction().begin(); + + /* + * Define query + */ + Query query = em.createQuery( + "Select i from IntegrityAuditEntity i where i.persistenceUnit=:pu and i.nodeType=:nt"); + query.setParameter("pu", persistenceUnit); + query.setParameter("nt", nodeType); + + /* + * Execute query using pessimistic write lock. This ensures that if anyone else is + * currently reading the records we'll throw a LockTimeoutException. + */ + @SuppressWarnings("unchecked") + List<IntegrityAuditEntity> integrityAuditEntityList = query.getResultList(); + for (Object o : integrityAuditEntityList) { + if (o instanceof IntegrityAuditEntity) { + IntegrityAuditEntity integrityAuditEntity = (IntegrityAuditEntity) o; + if (integrityAuditEntity.getResourceName().equals(resourceName)) { + if (logger.isDebugEnabled()) { + logger.debug("changeDesignated: Designating resourceName=" + + integrityAuditEntity.getResourceName()); + } + integrityAuditEntity.setDesignated(true); + } else { + if (logger.isDebugEnabled()) { + logger.debug("changeDesignated: Removing designation from resourceName=" + + integrityAuditEntity.getResourceName()); + } + integrityAuditEntity.setDesignated(false); + } + } + } + + if (logger.isDebugEnabled()) { + logger.debug("changeDesignated: Committing designation to resourceName=" + resourceName); + } + em.getTransaction().commit(); + + /* + * If we get a LockTimeoutException, no harm done really. We'll probably be + * successful on the next attempt. The odds of another DbDAO instance on this entity + * or another entity attempting a simultaneous IntegrityAuditEntity table + * read/update are pretty slim (we're only in this method for two or three + * milliseconds) + */ + } catch (LockTimeoutException e) { + if (em != null) { + em.getTransaction().rollback(); + + String msg = "DbDAO: " + "changeDesignated() " + "caught LockTimeoutException, message=" + + e.getMessage(); + logger.error(msg + e); + throw new DbDaoTransactionException(msg, e); + } else { + String msg = "DbDAO: " + "changeDesignated() " + "caught LockTimeoutException, message=" + + e.getMessage() + ". Error rolling back transaction."; + logger.error(msg + e); + throw new DbDaoTransactionException(msg, e); + } + } catch (Exception e) { + if (em != null) { + em.getTransaction().rollback(); + + String msg = "DbDAO: " + "changeDesignated() " + "caught Exception, message=" + e.getMessage(); + logger.error(msg + e); + throw new DbDaoTransactionException(msg, e); + } else { + String msg = "DbDAO: " + "changeDesignated() " + "caught LockTimeoutException, message=" + + e.getMessage() + ". Error rolling back transaction."; + logger.error(msg + e); + throw new DbDaoTransactionException(msg, e); + } + } + + } // end synchronized block + + if (logger.isDebugEnabled()) { + logger.debug("changeDesignated: Exiting; time expended=" + (System.currentTimeMillis() - startTime) + "ms"); + } + + } } diff --git a/integrity-audit/src/main/java/org/onap/policy/common/ia/DbDaoTransactionException.java b/integrity-audit/src/main/java/org/onap/policy/common/ia/DbDaoTransactionException.java index 72716279..dc1c6f14 100644 --- a/integrity-audit/src/main/java/org/onap/policy/common/ia/DbDaoTransactionException.java +++ b/integrity-audit/src/main/java/org/onap/policy/common/ia/DbDaoTransactionException.java @@ -21,18 +21,21 @@ package org.onap.policy.common.ia; public class DbDaoTransactionException extends IntegrityAuditException { - private static final long serialVersionUID = 1L; - public DbDaoTransactionException() { - super(); - } - public DbDaoTransactionException(String message) { - super(message); - } + private static final long serialVersionUID = 1L; - public DbDaoTransactionException(Throwable cause) { - super(cause); - } - public DbDaoTransactionException(String message, Throwable cause) { - super(message, cause); - } + public DbDaoTransactionException() { + super(); + } + + public DbDaoTransactionException(String message) { + super(message); + } + + public DbDaoTransactionException(Throwable cause) { + super(cause); + } + + public DbDaoTransactionException(String message, Throwable cause) { + super(message, cause); + } } diff --git a/integrity-audit/src/main/java/org/onap/policy/common/ia/IntegrityAudit.java b/integrity-audit/src/main/java/org/onap/policy/common/ia/IntegrityAudit.java index cab08610..9abdbe52 100644 --- a/integrity-audit/src/main/java/org/onap/policy/common/ia/IntegrityAudit.java +++ b/integrity-audit/src/main/java/org/onap/policy/common/ia/IntegrityAudit.java @@ -26,275 +26,277 @@ import java.util.concurrent.CountDownLatch; import org.onap.policy.common.ia.IntegrityAuditProperties.NodeTypeEnum; import org.onap.policy.common.logging.flexlogger.FlexLogger; -import org.onap.policy.common.logging.flexlogger.Logger; +import org.onap.policy.common.logging.flexlogger.Logger; /** - * class IntegrityAudit - * Audits all persisted entities for all resource clusters for all sites and logs any anomalies. + * class IntegrityAudit Audits all persisted entities for all resource clusters for all sites and + * logs any anomalies. */ public class IntegrityAudit { - - private static final Logger logger = FlexLogger.getLogger(IntegrityAudit.class); - - private static boolean isUnitTesting; - private boolean isThreadInitialized = false; - - AuditThread auditThread = null; - - private String persistenceUnit; - private Properties properties; - private String resourceName; - - - /* - * This is the audit period in milliseconds. For example, if it had a value of 3600000, the audit - * can only run once per hour. If it has a value of 6000, it can run once per minute. - * - * Values: - * integrityAuditPeriodMillis < 0 (negative number) indicates the audit is off - * integrityAuditPeriodMillis == 0 indicates the audit is to run continuously - * integrityAuditPeriodMillis > 0 indicates the audit is to run at most once during the indicated period - * - */ - private int integrityAuditPeriodMillis; - - /** - * IntegrityAudit constructor - * @param resourceName - * @param persistenceUnit - * @param properties - * @throws IntegrityAuditException - */ - public IntegrityAudit(String resourceName, String persistenceUnit, Properties properties) throws IntegrityAuditException { - - logger.info("Constructor: Entering and checking for nulls"); - StringBuilder parmList = new StringBuilder(); - if (parmsAreBad(resourceName, persistenceUnit, properties, parmList)) { - logger.error("Constructor: Parms contain nulls; cannot run audit for resourceName=" - + resourceName + ", persistenceUnit=" + persistenceUnit - + ", bad parameters: " + parmList); - throw new IntegrityAuditException( - "Constructor: Parms contain nulls; cannot run audit for resourceName=" - + resourceName + ", persistenceUnit=" - + persistenceUnit - + ", bad parameters: " + parmList); - } - - this.persistenceUnit = persistenceUnit; - this.properties = properties; - this.resourceName = resourceName; - - if(properties.getProperty(IntegrityAuditProperties.AUDIT_PERIOD_SECONDS) != null){ //It is allowed to be null - this.integrityAuditPeriodMillis= 1000 * Integer.parseInt(properties.getProperty(IntegrityAuditProperties.AUDIT_PERIOD_SECONDS).trim()); - } else if(properties.getProperty(IntegrityAuditProperties.AUDIT_PERIOD_MILLISECONDS) != null){ //It is allowed to be null - this.integrityAuditPeriodMillis= Integer.parseInt(properties.getProperty(IntegrityAuditProperties.AUDIT_PERIOD_MILLISECONDS).trim()); - } else{ - //If it is null, set it to the default value - this.integrityAuditPeriodMillis = 1000 * IntegrityAuditProperties.DEFAULT_AUDIT_PERIOD_SECONDS; - } - logger.info("Constructor: Exiting"); - - } - - /** - * Used during JUnit testing by AuditPeriodTest.java - */ - public int getIntegrityAuditPeriodSeconds() { - return (integrityAuditPeriodMillis / 1000); - } - - /** - * Determine if the nodeType conforms to the required node types - */ - public static boolean isNodeTypeEnum(String nt) { - for (NodeTypeEnum n : NodeTypeEnum.values()) { - if (n.toString().equals(nt)) { - return true; - } - } - return false; - } - - - /** - * Makes sure we don't try to run the audit with bad parameters. - */ - public static boolean parmsAreBad(String resourceName, String persistenceUnit, - Properties properties, StringBuilder badparams) { - - boolean parmsAreBad = false; - - if(resourceName == null || resourceName.isEmpty()){ - badparams.append("resourceName "); - parmsAreBad = true; - } - - if(persistenceUnit == null || persistenceUnit.isEmpty()){ - badparams.append("persistenceUnit "); - parmsAreBad = true; - } - - if(properties == null || properties.isEmpty()){ - badparams.append("properties "); - parmsAreBad = true; - } - else{ - String dbDriver = properties.getProperty(IntegrityAuditProperties.DB_DRIVER); - if(dbDriver == null || dbDriver.isEmpty()){ - badparams.append("dbDriver "); - parmsAreBad = true; - } - - String dbUrl = properties.getProperty(IntegrityAuditProperties.DB_URL); - if(dbUrl == null || dbUrl.isEmpty()){ - badparams.append("dbUrl "); - parmsAreBad = true; - } - - String dbUser = properties.getProperty(IntegrityAuditProperties.DB_USER); - if(dbUser == null || dbUser.isEmpty()){ - badparams.append("dbUser "); - parmsAreBad = true; - } - - String dbPwd = properties.getProperty(IntegrityAuditProperties.DB_PWD); - if(dbPwd == null){ //may be empty - badparams.append("dbPwd "); - parmsAreBad = true; - } - - String siteName = properties.getProperty(IntegrityAuditProperties.SITE_NAME); - if(siteName == null || siteName.isEmpty()){ - badparams.append("siteName "); - parmsAreBad = true; - } - - String nodeType = properties.getProperty(IntegrityAuditProperties.NODE_TYPE); - if(nodeType == null || nodeType.isEmpty()){ - badparams.append("nodeType "); - parmsAreBad = true; - } else { - nodeType = nodeType.trim(); - if (!isNodeTypeEnum(nodeType)) { - String nodetypes = "nodeType must be one of["; - for (NodeTypeEnum n : NodeTypeEnum.values()) { - nodetypes = nodetypes.concat(n.toString() + " "); - } - badparams.append(nodetypes + "] "); - parmsAreBad = true; - } - } - if(properties.getProperty(IntegrityAuditProperties.AUDIT_PERIOD_SECONDS) != null){ //It is allowed to be null - try{ - Integer.parseInt(properties.getProperty(IntegrityAuditProperties.AUDIT_PERIOD_SECONDS).trim()); - }catch(NumberFormatException nfe){ - badparams.append(", auditPeriodSeconds=" - + properties.getProperty(IntegrityAuditProperties.AUDIT_PERIOD_SECONDS).trim()); - parmsAreBad = true; - } - } - else if(properties.getProperty(IntegrityAuditProperties.AUDIT_PERIOD_MILLISECONDS) != null){ //It is allowed to be null - try{ - Integer.parseInt(properties.getProperty(IntegrityAuditProperties.AUDIT_PERIOD_MILLISECONDS).trim()); - }catch(NumberFormatException nfe){ - badparams.append(", auditPeriodMilliSeconds=" - + properties.getProperty(IntegrityAuditProperties.AUDIT_PERIOD_MILLISECONDS).trim()); - parmsAreBad = true; - } - } - } // End else - logger.debug("parmsAreBad: exit:" - + "\nresourceName: " + resourceName - + "\npersistenceUnit: " + persistenceUnit - + "\nproperties: " + properties); - - return parmsAreBad; - } - /** - * Starts the audit thread - * @throws IntegrityAuditException - */ - public void startAuditThread() throws IntegrityAuditException { - startAuditThread(null); - } - /** - * Starts the audit thread - * @param queue - * @return {@code true} if the thread was started, {@code false} otherwise - * @throws IntegrityAuditException - */ - protected boolean startAuditThread(BlockingQueue<CountDownLatch> queue) throws IntegrityAuditException { - - logger.info("startAuditThread: Entering"); - - boolean success = false; - - if (integrityAuditPeriodMillis >= 0) { - this.auditThread = new AuditThread(this.resourceName, - this.persistenceUnit, this.properties, - integrityAuditPeriodMillis, this, queue); - logger.info("startAuditThread: Audit started and will run every " - + integrityAuditPeriodMillis/1000 + " seconds"); - this.auditThread.start(); - success = true; - } else { - logger.info("startAuditThread: Suppressing integrity audit, integrityAuditPeriodSeconds=" - + integrityAuditPeriodMillis/1000); - } - - logger.info("startAuditThread: Exiting"); - - return success; - } - /** - * Stops the audit thread - */ - public void stopAuditThread() { - - logger.info("stopAuditThread: Entering"); - - if (this.auditThread != null) { - this.auditThread.interrupt(); - } else { - logger.info("stopAuditThread: auditThread never instantiated; no need to interrupt"); - } - - logger.info("stopAuditThread: Exiting"); - } - - public boolean isThreadInitialized() { - return isThreadInitialized; - } - - public void setThreadInitialized(boolean isThreadInitialized) { - logger.info("setThreadInitialized: Setting isThreadInitialized=" + isThreadInitialized); - this.isThreadInitialized = isThreadInitialized; - } - - public static boolean isUnitTesting() { - return isUnitTesting; - } - - public static void setUnitTesting(boolean isUnitTesting) { - IntegrityAudit.isUnitTesting = isUnitTesting; - } - - /** - * Waits a bit for the AuditThread to complete. Used by JUnit tests. - * - * @param twaitms - * wait time, in milliseconds - * @return {@code true} if the thread stopped within the given time, - * {@code false} otherwise - * @throws InterruptedException - */ - protected boolean joinAuditThread(long twaitms) throws InterruptedException { - if(this.auditThread == null) { - return true; - - } else { - this.auditThread.join(twaitms); - return ! this.auditThread.isAlive(); - } - } + + private static final Logger logger = FlexLogger.getLogger(IntegrityAudit.class); + + private static boolean isUnitTesting; + private boolean isThreadInitialized = false; + + AuditThread auditThread = null; + + private String persistenceUnit; + private Properties properties; + private String resourceName; + + + /* + * This is the audit period in milliseconds. For example, if it had a value of 3600000, the + * audit can only run once per hour. If it has a value of 6000, it can run once per minute. + * + * Values: integrityAuditPeriodMillis < 0 (negative number) indicates the audit is off + * integrityAuditPeriodMillis == 0 indicates the audit is to run continuously + * integrityAuditPeriodMillis > 0 indicates the audit is to run at most once during the + * indicated period + * + */ + private int integrityAuditPeriodMillis; + + /** + * IntegrityAudit constructor. + * + * @param resourceName the resource name + * @param persistenceUnit the persistence unit + * @param properties the properties + * @throws IntegrityAuditException if an error occurs + */ + public IntegrityAudit(String resourceName, String persistenceUnit, Properties properties) + throws IntegrityAuditException { + + logger.info("Constructor: Entering and checking for nulls"); + StringBuilder parmList = new StringBuilder(); + if (parmsAreBad(resourceName, persistenceUnit, properties, parmList)) { + logger.error("Constructor: Parms contain nulls; cannot run audit for resourceName=" + resourceName + + ", persistenceUnit=" + persistenceUnit + ", bad parameters: " + parmList); + throw new IntegrityAuditException("Constructor: Parms contain nulls; cannot run audit for resourceName=" + + resourceName + ", persistenceUnit=" + persistenceUnit + ", bad parameters: " + parmList); + } + + this.persistenceUnit = persistenceUnit; + this.properties = properties; + this.resourceName = resourceName; + + // IntegrityAuditProperties.AUDIT_PERIOD_SECONDS and + // IntegrityAuditProperties.AUDIT_PERIOD_MILLISECONDS are allowed to be null + if (properties.getProperty(IntegrityAuditProperties.AUDIT_PERIOD_SECONDS) != null) { + this.integrityAuditPeriodMillis = 1000 + * Integer.parseInt(properties.getProperty(IntegrityAuditProperties.AUDIT_PERIOD_SECONDS).trim()); + } else if (properties.getProperty(IntegrityAuditProperties.AUDIT_PERIOD_MILLISECONDS) != null) { + this.integrityAuditPeriodMillis = + Integer.parseInt(properties.getProperty(IntegrityAuditProperties.AUDIT_PERIOD_MILLISECONDS).trim()); + } else { + // If it is null, set it to the default value + this.integrityAuditPeriodMillis = 1000 * IntegrityAuditProperties.DEFAULT_AUDIT_PERIOD_SECONDS; + } + logger.info("Constructor: Exiting"); + + } + + /** + * Used during JUnit testing by AuditPeriodTest.java + */ + public int getIntegrityAuditPeriodSeconds() { + return (integrityAuditPeriodMillis / 1000); + } + + /** + * Determine if the nodeType conforms to the required node types. + */ + public static boolean isNodeTypeEnum(String nt) { + for (NodeTypeEnum n : NodeTypeEnum.values()) { + if (n.toString().equals(nt)) { + return true; + } + } + return false; + } + + + /** + * Makes sure we don't try to run the audit with bad parameters. + */ + public static boolean parmsAreBad(String resourceName, String persistenceUnit, Properties properties, + StringBuilder badparams) { + + boolean parmsAreBad = false; + + if (resourceName == null || resourceName.isEmpty()) { + badparams.append("resourceName "); + parmsAreBad = true; + } + + if (persistenceUnit == null || persistenceUnit.isEmpty()) { + badparams.append("persistenceUnit "); + parmsAreBad = true; + } + + if (properties == null || properties.isEmpty()) { + badparams.append("properties "); + parmsAreBad = true; + } else { + String dbDriver = properties.getProperty(IntegrityAuditProperties.DB_DRIVER); + if (dbDriver == null || dbDriver.isEmpty()) { + badparams.append("dbDriver "); + parmsAreBad = true; + } + + String dbUrl = properties.getProperty(IntegrityAuditProperties.DB_URL); + if (dbUrl == null || dbUrl.isEmpty()) { + badparams.append("dbUrl "); + parmsAreBad = true; + } + + String dbUser = properties.getProperty(IntegrityAuditProperties.DB_USER); + if (dbUser == null || dbUser.isEmpty()) { + badparams.append("dbUser "); + parmsAreBad = true; + } + + String dbPwd = properties.getProperty(IntegrityAuditProperties.DB_PWD); + if (dbPwd == null) { // may be empty + badparams.append("dbPwd "); + parmsAreBad = true; + } + + String siteName = properties.getProperty(IntegrityAuditProperties.SITE_NAME); + if (siteName == null || siteName.isEmpty()) { + badparams.append("siteName "); + parmsAreBad = true; + } + + String nodeType = properties.getProperty(IntegrityAuditProperties.NODE_TYPE); + if (nodeType == null || nodeType.isEmpty()) { + badparams.append("nodeType "); + parmsAreBad = true; + } else { + nodeType = nodeType.trim(); + if (!isNodeTypeEnum(nodeType)) { + String nodetypes = "nodeType must be one of["; + for (NodeTypeEnum n : NodeTypeEnum.values()) { + nodetypes = nodetypes.concat(n.toString() + " "); + } + badparams.append(nodetypes + "] "); + parmsAreBad = true; + } + } + // IntegrityAuditProperties.AUDIT_PERIOD_SECONDS and + // IntegrityAuditProperties.AUDIT_PERIOD_MILLISECONDS are allowed to be null + if (properties.getProperty(IntegrityAuditProperties.AUDIT_PERIOD_SECONDS) != null) { + try { + Integer.parseInt(properties.getProperty(IntegrityAuditProperties.AUDIT_PERIOD_SECONDS).trim()); + } catch (NumberFormatException nfe) { + badparams.append(", auditPeriodSeconds=" + + properties.getProperty(IntegrityAuditProperties.AUDIT_PERIOD_SECONDS).trim()); + parmsAreBad = true; + } + } else if (properties.getProperty(IntegrityAuditProperties.AUDIT_PERIOD_MILLISECONDS) != null) { + try { + Integer.parseInt(properties.getProperty(IntegrityAuditProperties.AUDIT_PERIOD_MILLISECONDS).trim()); + } catch (NumberFormatException nfe) { + badparams.append(", auditPeriodMilliSeconds=" + + properties.getProperty(IntegrityAuditProperties.AUDIT_PERIOD_MILLISECONDS).trim()); + parmsAreBad = true; + } + } + } // End else + logger.debug("parmsAreBad: exit:" + "\nresourceName: " + resourceName + "\npersistenceUnit: " + persistenceUnit + + "\nproperties: " + properties); + + return parmsAreBad; + } + + /** + * Starts the audit thread. + * + * @throws IntegrityAuditException if an error occurs + */ + public void startAuditThread() throws IntegrityAuditException { + startAuditThread(null); + } + + /** + * Starts the audit thread. + * + * @param queue the queue + * @return {@code true} if the thread was started, {@code false} otherwise + * @throws IntegrityAuditException if an error occurs + */ + protected boolean startAuditThread(BlockingQueue<CountDownLatch> queue) throws IntegrityAuditException { + + logger.info("startAuditThread: Entering"); + + boolean success = false; + + if (integrityAuditPeriodMillis >= 0) { + this.auditThread = new AuditThread(this.resourceName, this.persistenceUnit, this.properties, + integrityAuditPeriodMillis, this, queue); + logger.info("startAuditThread: Audit started and will run every " + integrityAuditPeriodMillis / 1000 + + " seconds"); + this.auditThread.start(); + success = true; + } else { + logger.info("startAuditThread: Suppressing integrity audit, integrityAuditPeriodSeconds=" + + integrityAuditPeriodMillis / 1000); + } + + logger.info("startAuditThread: Exiting"); + + return success; + } + + /** + * Stops the audit thread. + */ + public void stopAuditThread() { + + logger.info("stopAuditThread: Entering"); + + if (this.auditThread != null) { + this.auditThread.interrupt(); + } else { + logger.info("stopAuditThread: auditThread never instantiated; no need to interrupt"); + } + + logger.info("stopAuditThread: Exiting"); + } + + public boolean isThreadInitialized() { + return isThreadInitialized; + } + + public void setThreadInitialized(boolean isThreadInitialized) { + logger.info("setThreadInitialized: Setting isThreadInitialized=" + isThreadInitialized); + this.isThreadInitialized = isThreadInitialized; + } + + public static boolean isUnitTesting() { + return isUnitTesting; + } + + public static void setUnitTesting(boolean isUnitTesting) { + IntegrityAudit.isUnitTesting = isUnitTesting; + } + + /** + * Waits a bit for the AuditThread to complete. Used by JUnit tests. + * + * @param twaitms wait time, in milliseconds + * @return {@code true} if the thread stopped within the given time, {@code false} otherwise + * @throws InterruptedException if the thread is interrupted + */ + protected boolean joinAuditThread(long twaitms) throws InterruptedException { + if (this.auditThread == null) { + return true; + + } else { + this.auditThread.join(twaitms); + return !this.auditThread.isAlive(); + } + } } diff --git a/integrity-audit/src/main/java/org/onap/policy/common/ia/IntegrityAuditException.java b/integrity-audit/src/main/java/org/onap/policy/common/ia/IntegrityAuditException.java index a62c837c..81e8b90c 100644 --- a/integrity-audit/src/main/java/org/onap/policy/common/ia/IntegrityAuditException.java +++ b/integrity-audit/src/main/java/org/onap/policy/common/ia/IntegrityAuditException.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * Integrity Audit * ================================================================================ - * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,19 +20,22 @@ package org.onap.policy.common.ia; -public class IntegrityAuditException extends Exception{ - private static final long serialVersionUID = 1L; - public IntegrityAuditException() { - super(); - } - public IntegrityAuditException(String message) { - super(message); - } +public class IntegrityAuditException extends Exception { + private static final long serialVersionUID = 1L; - public IntegrityAuditException(Throwable cause) { - super(cause); - } - public IntegrityAuditException(String message, Throwable cause) { - super(message, cause); - } + public IntegrityAuditException() { + super(); + } + + public IntegrityAuditException(String message) { + super(message); + } + + public IntegrityAuditException(Throwable cause) { + super(cause); + } + + public IntegrityAuditException(String message, Throwable cause) { + super(message, cause); + } } diff --git a/integrity-audit/src/main/java/org/onap/policy/common/ia/IntegrityAuditProperties.java b/integrity-audit/src/main/java/org/onap/policy/common/ia/IntegrityAuditProperties.java index b8db3ac2..2708c090 100644 --- a/integrity-audit/src/main/java/org/onap/policy/common/ia/IntegrityAuditProperties.java +++ b/integrity-audit/src/main/java/org/onap/policy/common/ia/IntegrityAuditProperties.java @@ -22,34 +22,26 @@ package org.onap.policy.common.ia; public class IntegrityAuditProperties { - public static final int DEFAULT_AUDIT_PERIOD_SECONDS = -1; // Audit does not run - - public static final String DB_DRIVER = "javax.persistence.jdbc.driver"; - public static final String DB_URL = "javax.persistence.jdbc.url"; - public static final String DB_USER = "javax.persistence.jdbc.user"; - public static final String DB_PWD = "javax.persistence.jdbc.password"; - public static final String AUDIT_PERIOD_SECONDS = "integrity_audit_period_seconds"; - public static final String AUDIT_PERIOD_MILLISECONDS = "integrity_audit_period_milliseconds"; - - - public static final String SITE_NAME = "site_name"; - public static final String NODE_TYPE = "node_type"; - - public enum NodeTypeEnum { - pdp_xacml, - pdp_drools, - pap, - pap_admin, - logparser, - brms_gateway, - astra_gateway, - elk_server, - pypdp - - } - - private IntegrityAuditProperties() { - - } - + public static final int DEFAULT_AUDIT_PERIOD_SECONDS = -1; // Audit does not run + + public static final String DB_DRIVER = "javax.persistence.jdbc.driver"; + public static final String DB_URL = "javax.persistence.jdbc.url"; + public static final String DB_USER = "javax.persistence.jdbc.user"; + public static final String DB_PWD = "javax.persistence.jdbc.password"; + public static final String AUDIT_PERIOD_SECONDS = "integrity_audit_period_seconds"; + public static final String AUDIT_PERIOD_MILLISECONDS = "integrity_audit_period_milliseconds"; + + + public static final String SITE_NAME = "site_name"; + public static final String NODE_TYPE = "node_type"; + + public enum NodeTypeEnum { + pdp_xacml, pdp_drools, pap, pap_admin, logparser, brms_gateway, astra_gateway, elk_server, pypdp + + } + + private IntegrityAuditProperties() { + + } + } diff --git a/integrity-audit/src/main/java/org/onap/policy/common/ia/IntegrityAuditPropertiesException.java b/integrity-audit/src/main/java/org/onap/policy/common/ia/IntegrityAuditPropertiesException.java index 766268bc..d3c92fa5 100644 --- a/integrity-audit/src/main/java/org/onap/policy/common/ia/IntegrityAuditPropertiesException.java +++ b/integrity-audit/src/main/java/org/onap/policy/common/ia/IntegrityAuditPropertiesException.java @@ -21,18 +21,21 @@ package org.onap.policy.common.ia; public class IntegrityAuditPropertiesException extends IntegrityAuditException { - private static final long serialVersionUID = 1L; - public IntegrityAuditPropertiesException() { - super(); - } - public IntegrityAuditPropertiesException(String message) { - super(message); - } + private static final long serialVersionUID = 1L; - public IntegrityAuditPropertiesException(Throwable cause) { - super(cause); - } - public IntegrityAuditPropertiesException(String message, Throwable cause) { - super(message, cause); - } + public IntegrityAuditPropertiesException() { + super(); + } + + public IntegrityAuditPropertiesException(String message) { + super(message); + } + + public IntegrityAuditPropertiesException(Throwable cause) { + super(cause); + } + + public IntegrityAuditPropertiesException(String message, Throwable cause) { + super(message, cause); + } } diff --git a/integrity-audit/src/main/java/org/onap/policy/common/ia/jpa/IntegrityAuditEntity.java b/integrity-audit/src/main/java/org/onap/policy/common/ia/jpa/IntegrityAuditEntity.java index da69f2de..23b90efc 100644 --- a/integrity-audit/src/main/java/org/onap/policy/common/ia/jpa/IntegrityAuditEntity.java +++ b/integrity-audit/src/main/java/org/onap/policy/common/ia/jpa/IntegrityAuditEntity.java @@ -42,184 +42,185 @@ import javax.persistence.TemporalType; */ @Entity -@Table(name="IntegrityAuditEntity") -@NamedQueries({ - @NamedQuery(name=" IntegrityAuditEntity.findAll", query="SELECT e FROM IntegrityAuditEntity e "), - @NamedQuery(name="IntegrityAuditEntity.deleteAll", query="DELETE FROM IntegrityAuditEntity WHERE 1=1") -}) +@Table(name = "IntegrityAuditEntity") +@NamedQueries({@NamedQuery(name = " IntegrityAuditEntity.findAll", query = "SELECT e FROM IntegrityAuditEntity e "), + @NamedQuery(name = "IntegrityAuditEntity.deleteAll", query = "DELETE FROM IntegrityAuditEntity WHERE 1=1")}) public class IntegrityAuditEntity implements Serializable { - private static final long serialVersionUID = 1L; - - private static boolean isUnitTesting; - - @Id - @GeneratedValue(strategy = GenerationType.AUTO) - @Column(name="id") - private long id; - - @Column(name="persistenceUnit", nullable=false) - private String persistenceUnit; - - @Column(name="site", nullable=true) - private String site; - - @Column(name="nodeType", nullable=true) - private String nodeType; - - @Column(name="resourceName", nullable=false, unique=true) - private String resourceName; - - @Column(name="designated", nullable=true) - private boolean designated = false; - - @Column(name="jdbcDriver", nullable=false) - private String jdbcDriver; - - @Column(name="jdbcUrl", nullable=false) - private String jdbcUrl; - - @Column(name="jdbcUser", nullable=false) - private String jdbcUser; - - @Column(name="jdbcPassword", nullable=false) - private String jdbcPassword; - - @Temporal(TemporalType.TIMESTAMP) - @Column(name="createdDate", updatable=true) - private Date createdDate; - - @Temporal(TemporalType.TIMESTAMP) - @Column(name="lastUpdated") - private Date lastUpdated; - - - public IntegrityAuditEntity() { - // Empty constructor - } - - @PrePersist - public void prePersist() { - Date date = new Date(); - this.createdDate = date; - this.lastUpdated = date; - } - - @PreUpdate - public void preUpdate() { - this.lastUpdated = new Date(); - } - - public long getId() { - return id; - } - - public String getPersistenceUnit() { - return persistenceUnit; - } - - public void setPersistenceUnit(String persistenceUnit) { - this.persistenceUnit = persistenceUnit; - } - - public String getSite() { - return site; - } - - public void setSite(String site) { - this.site = site; - } - - public String getNodeType() { - return nodeType; - } - - public void setNodeType(String nodeType) { - this.nodeType = nodeType; - } - - public String getResourceName() { - return resourceName; - } - - public void setResourceName(String resourceName) { - this.resourceName = resourceName; - } - - public boolean isDesignated() { - return designated; - } - - public void setDesignated(boolean designated) { - this.designated = designated; - } - - public String getJdbcDriver() { - return jdbcDriver; - } - - public void setJdbcDriver(String jdbcDriver) { - this.jdbcDriver = jdbcDriver; - } - - public String getJdbcUrl() { - return jdbcUrl; - } - - public void setJdbcUrl(String jdbcUrl) { - this.jdbcUrl = jdbcUrl; - } - - public String getJdbcUser() { - return jdbcUser; - } - - public void setJdbcUser(String jdbcUser) { - this.jdbcUser = jdbcUser; - } - - public String getJdbcPassword() { - return jdbcPassword; - } - - public void setJdbcPassword(String jdbcPassword) { - this.jdbcPassword = jdbcPassword; - } - - public Date getLastUpdated() { - return lastUpdated; - } - - public void setLastUpdated(Date lastUpdated) { - this.lastUpdated = lastUpdated; - } - - public Date getCreatedDate() { - return createdDate; - } - - public void setCreatedDate(Date created) { - this.createdDate = created; - } - - public static boolean isUnitTesting() { - return isUnitTesting; - } - - public static void setUnitTesting(boolean isUnitTesting) { - IntegrityAuditEntity.isUnitTesting = isUnitTesting; - } - - private void writeObject(ObjectOutputStream out) throws IOException { - if(isUnitTesting()) { - /* - * Note: other fields may be added here, as long as the - * created-date and last-updated date are not included. - */ - out.writeObject(jdbcUrl); - - } else { - out.defaultWriteObject(); - } - } + private static final long serialVersionUID = 1L; + + private static boolean isUnitTesting; + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + @Column(name = "id") + private long id; + + @Column(name = "persistenceUnit", nullable = false) + private String persistenceUnit; + + @Column(name = "site", nullable = true) + private String site; + + @Column(name = "nodeType", nullable = true) + private String nodeType; + + @Column(name = "resourceName", nullable = false, unique = true) + private String resourceName; + + @Column(name = "designated", nullable = true) + private boolean designated = false; + + @Column(name = "jdbcDriver", nullable = false) + private String jdbcDriver; + + @Column(name = "jdbcUrl", nullable = false) + private String jdbcUrl; + + @Column(name = "jdbcUser", nullable = false) + private String jdbcUser; + + @Column(name = "jdbcPassword", nullable = false) + private String jdbcPassword; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "createdDate", updatable = true) + private Date createdDate; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "lastUpdated") + private Date lastUpdated; + + + public IntegrityAuditEntity() { + // Empty constructor + } + + /** + * Pre persist. + */ + @PrePersist + public void prePersist() { + Date date = new Date(); + this.createdDate = date; + this.lastUpdated = date; + } + + @PreUpdate + public void preUpdate() { + this.lastUpdated = new Date(); + } + + public long getId() { + return id; + } + + public String getPersistenceUnit() { + return persistenceUnit; + } + + public void setPersistenceUnit(String persistenceUnit) { + this.persistenceUnit = persistenceUnit; + } + + public String getSite() { + return site; + } + + public void setSite(String site) { + this.site = site; + } + + public String getNodeType() { + return nodeType; + } + + public void setNodeType(String nodeType) { + this.nodeType = nodeType; + } + + public String getResourceName() { + return resourceName; + } + + public void setResourceName(String resourceName) { + this.resourceName = resourceName; + } + + public boolean isDesignated() { + return designated; + } + + public void setDesignated(boolean designated) { + this.designated = designated; + } + + public String getJdbcDriver() { + return jdbcDriver; + } + + public void setJdbcDriver(String jdbcDriver) { + this.jdbcDriver = jdbcDriver; + } + + public String getJdbcUrl() { + return jdbcUrl; + } + + public void setJdbcUrl(String jdbcUrl) { + this.jdbcUrl = jdbcUrl; + } + + public String getJdbcUser() { + return jdbcUser; + } + + public void setJdbcUser(String jdbcUser) { + this.jdbcUser = jdbcUser; + } + + public String getJdbcPassword() { + return jdbcPassword; + } + + public void setJdbcPassword(String jdbcPassword) { + this.jdbcPassword = jdbcPassword; + } + + public Date getLastUpdated() { + return lastUpdated; + } + + public void setLastUpdated(Date lastUpdated) { + this.lastUpdated = lastUpdated; + } + + public Date getCreatedDate() { + return createdDate; + } + + public void setCreatedDate(Date created) { + this.createdDate = created; + } + + public static boolean isUnitTesting() { + return isUnitTesting; + } + + public static void setUnitTesting(boolean isUnitTesting) { + IntegrityAuditEntity.isUnitTesting = isUnitTesting; + } + + private void writeObject(ObjectOutputStream out) throws IOException { + if (isUnitTesting()) { + /* + * Note: other fields may be added here, as long as the created-date and last-updated + * date are not included. + */ + out.writeObject(jdbcUrl); + + } else { + out.defaultWriteObject(); + } + } } diff --git a/integrity-audit/src/test/java/org/onap/policy/common/ia/AuditPeriodTest.java b/integrity-audit/src/test/java/org/onap/policy/common/ia/AuditPeriodTest.java index b627977b..232468d6 100644 --- a/integrity-audit/src/test/java/org/onap/policy/common/ia/AuditPeriodTest.java +++ b/integrity-audit/src/test/java/org/onap/policy/common/ia/AuditPeriodTest.java @@ -44,217 +44,222 @@ import org.onap.policy.common.utils.test.log.logback.ExtractAppender; */ public class AuditPeriodTest extends IntegrityAuditTestBase { - private static Logger logger = FlexLogger.getLogger(AuditPeriodTest.class); + private static Logger logger = FlexLogger.getLogger(AuditPeriodTest.class); - @BeforeClass - public static void setUpBeforeClass() throws Exception { - IntegrityAuditTestBase.setUpBeforeClass(DEFAULT_DB_URL_PREFIX + AuditPeriodTest.class.getSimpleName()); - } + @BeforeClass + public static void setUpBeforeClass() throws Exception { + IntegrityAuditTestBase.setUpBeforeClass(DEFAULT_DB_URL_PREFIX + AuditPeriodTest.class.getSimpleName()); + } - @AfterClass - public static void tearDownAfterClass() { - IntegrityAuditTestBase.tearDownAfterClass(); - } + @AfterClass + public static void tearDownAfterClass() { + IntegrityAuditTestBase.tearDownAfterClass(); + } - @Before - public void setUp() { - logger.info("setUp: Entering"); + /** + * Set up for test case. + */ + @Override + @Before + public void setUp() { + logger.info("setUp: Entering"); - super.setUp(); + super.setUp(); - logger.info("setUp: Exiting"); + logger.info("setUp: Exiting"); - } + } - @After - public void tearDown() { - logger.info("tearDown: Entering"); + /** + * Tear down after test cases. + */ + @Override + @After + public void tearDown() { + logger.info("tearDown: Entering"); - super.tearDown(); + super.tearDown(); - logger.info("tearDown: Exiting"); - } + logger.info("tearDown: Exiting"); + } - /* - * Verifies (via log parsing) that when a negative audit period is - * specified, the audit is suppressed. - */ - @Test - public void testNegativeAuditPeriod() throws Exception { + /* + * Verifies (via log parsing) that when a negative audit period is specified, the audit is + * suppressed. + */ + @Test + public void testNegativeAuditPeriod() throws Exception { - logger.info("testNegativeAuditPeriod: Entering"); + logger.info("testNegativeAuditPeriod: Entering"); - properties.put(IntegrityAuditProperties.AUDIT_PERIOD_SECONDS, "-1"); + properties.put(IntegrityAuditProperties.AUDIT_PERIOD_SECONDS, "-1"); - ExtractAppender logA = watch(debugLogger, "Suppressing integrity audit, integrityAuditPeriodSeconds=([^,]*)"); + ExtractAppender logA = watch(debugLogger, "Suppressing integrity audit, integrityAuditPeriodSeconds=([^,]*)"); - MyIntegrityAudit integrityAudit = makeAuditor("pdp1", A_SEQ_PU); + MyIntegrityAudit integrityAudit = makeAuditor("pdp1", A_SEQ_PU); - /* - * Sleep long enough to allow - * - * 1) audit to immediately terminate. - */ - waitThread(integrityAudit); + /* + * Sleep long enough to allow + * + * 1) audit to immediately terminate. + */ + waitThread(integrityAudit); - verifyItemsInLog(logA, "-1"); + verifyItemsInLog(logA, "-1"); - logger.info("testNegativeAuditPeriod: Exiting"); - - } - - /* - * Verifies (via log parsing) that when an audit period of zero is - * specified, the audit runs continuously, generating a number of sleep/wake - * sequences in a short period of time (e.g. 100ms). - */ - @Test - public void testZeroAuditPeriod() throws Exception { - - logger.info("testZeroAuditPeriod: Entering"); - - properties.put(IntegrityAuditProperties.AUDIT_PERIOD_SECONDS, "0"); - - ExtractAppender logA = watch(debugLogger, "[Aa]waking from (0ms) sleep"); - - MyIntegrityAudit integrityAudit = makeAuditor("pdp1", A_SEQ_PU); - - /* - * Wait for - * - * 1) audit to generate a bunch of sleep wake sequences. - */ - String[] awakings = new String[10]; - for (int x = 0; x < awakings.length; ++x) { - awakings[x] = "0ms"; - runAudit(integrityAudit); - } - - // run a couple more audits - runAudit(integrityAudit); - runAudit(integrityAudit); - - /* - * We should get at least 10 sleep/wake sequences. - */ - - verifyItemsInLog(logA, awakings); - - logger.info("testZeroAuditPeriod: Exiting"); - - } - - /** - * Verifies that when different audit periods are specified, there is an - * appropriate interval between the audits. - */ - @Test - public void testLongAuditPeriod() throws Exception { - - logger.info("testLongAuditPeriod: Entering"); - - testAuditPeriod(100); - testAuditPeriod(200); - - logger.info("testLongAuditPeriod: Exiting"); - } - - /** - * Verifies that audits actually take as long as expected, even with - * multiple auditors running simultaneously. - * - * @param periodms - * audit period, in milliseconds - * @throws Exception - * @throws InterruptedException - */ - private void testAuditPeriod(long periodms) throws Exception, InterruptedException { - - properties.put(IntegrityAuditProperties.AUDIT_PERIOD_MILLISECONDS, String.valueOf(periodms)); - - /* - * Start several auditors. - */ - MyIntegrityAudit[] ia = new MyIntegrityAudit[3]; - for (int x = 0; x < ia.length; ++x) { - ia[x] = makeAuditor("pdp" + x, A_SEQ_PU); - } - - /* - * Run an audit on all of them. - */ - runAudit(ia); - - /* - * Now run again and ensure it waited long enough between runs. - */ - long tmin = minAuditTime(ia); - assertTrue(tmin >= periodms + AUDIT_SIMULATION_MS); - - /* - * Now run again and ensure it waited long enough between runs. - */ - tmin = minAuditTime(ia); - assertTrue(tmin >= periodms + AUDIT_SIMULATION_MS); - } - - /** - * Runs simultaneous audits on several auditors. - * - * @param auditors - * @return the minimum time, in milliseconds, elapsed for any given auditor - * @throws InterruptedException - */ - private long minAuditTime(MyIntegrityAudit... auditors) throws InterruptedException { - List<Thread> threads = new ArrayList<>(auditors.length); - AtomicLong tfirst = new AtomicLong(Long.MAX_VALUE); - long tbeg = System.currentTimeMillis(); - - // create the threads - for (MyIntegrityAudit p : auditors) { - Thread t = new Thread() { - - @Override - public void run() { - try { - runAudit(p); - setMinTime(tfirst); - - } catch (InterruptedException e) { - ; - } - } - }; - - t.setDaemon(true); - threads.add(t); - } - - // start the threads - for (Thread t : threads) { - t.start(); - } - - // wait for them to complete - for (Thread t : threads) { - t.join(); - } - - return (tfirst.get() - tbeg); - } - - /** - * Sets a value to the minimum between the current value and the current - * time. - * - * @param tmin - * current minimum value/value to be set - */ - private static void setMinTime(AtomicLong tmin) { - long tcur = System.currentTimeMillis(); - long t; - while ((t = tmin.get()) > tcur) { - tmin.compareAndSet(t, tcur); - } - } + logger.info("testNegativeAuditPeriod: Exiting"); + + } + + /* + * Verifies (via log parsing) that when an audit period of zero is specified, the audit runs + * continuously, generating a number of sleep/wake sequences in a short period of time (e.g. + * 100ms). + */ + @Test + public void testZeroAuditPeriod() throws Exception { + + logger.info("testZeroAuditPeriod: Entering"); + + properties.put(IntegrityAuditProperties.AUDIT_PERIOD_SECONDS, "0"); + + final ExtractAppender logA = watch(debugLogger, "[Aa]waking from (0ms) sleep"); + + MyIntegrityAudit integrityAudit = makeAuditor("pdp1", A_SEQ_PU); + + /* + * Wait for + * + * 1) audit to generate a bunch of sleep wake sequences. + */ + String[] awakings = new String[10]; + for (int x = 0; x < awakings.length; ++x) { + awakings[x] = "0ms"; + runAudit(integrityAudit); + } + + // run a couple more audits + runAudit(integrityAudit); + runAudit(integrityAudit); + + /* + * We should get at least 10 sleep/wake sequences. + */ + + verifyItemsInLog(logA, awakings); + + logger.info("testZeroAuditPeriod: Exiting"); + + } + + /** + * Verifies that when different audit periods are specified, there is an appropriate interval + * between the audits. + */ + @Test + public void testLongAuditPeriod() throws Exception { + + logger.info("testLongAuditPeriod: Entering"); + + testAuditPeriod(100); + testAuditPeriod(200); + + logger.info("testLongAuditPeriod: Exiting"); + } + + /** + * Verifies that audits actually take as long as expected, even with multiple auditors running + * simultaneously. + * + * @param periodms audit period, in milliseconds + * @throws Exception if an error occurs + * @throws InterruptedException if the thread is interrupted + */ + private void testAuditPeriod(long periodms) throws Exception, InterruptedException { + + properties.put(IntegrityAuditProperties.AUDIT_PERIOD_MILLISECONDS, String.valueOf(periodms)); + + /* + * Start several auditors. + */ + MyIntegrityAudit[] ia = new MyIntegrityAudit[3]; + for (int x = 0; x < ia.length; ++x) { + ia[x] = makeAuditor("pdp" + x, A_SEQ_PU); + } + + /* + * Run an audit on all of them. + */ + runAudit(ia); + + /* + * Now run again and ensure it waited long enough between runs. + */ + long tmin = minAuditTime(ia); + assertTrue(tmin >= periodms + AUDIT_SIMULATION_MS); + + /* + * Now run again and ensure it waited long enough between runs. + */ + tmin = minAuditTime(ia); + assertTrue(tmin >= periodms + AUDIT_SIMULATION_MS); + } + + /** + * Runs simultaneous audits on several auditors. + * + * @param auditors the auditors + * @return the minimum time, in milliseconds, elapsed for any given auditor + * @throws InterruptedException if the thread is interrupted + */ + private long minAuditTime(MyIntegrityAudit... auditors) throws InterruptedException { + List<Thread> threads = new ArrayList<>(auditors.length); + AtomicLong tfirst = new AtomicLong(Long.MAX_VALUE); + final long tbeg = System.currentTimeMillis(); + + // create the threads + for (MyIntegrityAudit p : auditors) { + Thread auditThread = new Thread() { + + @Override + public void run() { + try { + runAudit(p); + setMinTime(tfirst); + + } catch (InterruptedException e) { + ; + } + } + }; + + auditThread.setDaemon(true); + threads.add(auditThread); + } + + // start the threads + for (Thread t : threads) { + t.start(); + } + + // wait for them to complete + for (Thread t : threads) { + t.join(); + } + + return (tfirst.get() - tbeg); + } + + /** + * Sets a value to the minimum between the current value and the current time. + * + * @param tmin current minimum value/value to be set + */ + private static void setMinTime(AtomicLong tmin) { + long tcur = System.currentTimeMillis(); + long time; + while ((time = tmin.get()) > tcur) { + tmin.compareAndSet(time, tcur); + } + } } diff --git a/integrity-audit/src/test/java/org/onap/policy/common/ia/DbAuditCompareEntriesTest.java b/integrity-audit/src/test/java/org/onap/policy/common/ia/DbAuditCompareEntriesTest.java index 3a48b20c..6335482a 100644 --- a/integrity-audit/src/test/java/org/onap/policy/common/ia/DbAuditCompareEntriesTest.java +++ b/integrity-audit/src/test/java/org/onap/policy/common/ia/DbAuditCompareEntriesTest.java @@ -50,505 +50,507 @@ import org.onap.policy.common.logging.flexlogger.Logger; */ public class DbAuditCompareEntriesTest extends IntegrityAuditTestBase { - private static Logger logger = FlexLogger.getLogger(DbAuditCompareEntriesTest.class); - - private DbDAO dbDAO; - private static String resourceName = "pdp1"; - - @BeforeClass - public static void setUpBeforeClass() throws Exception { - IntegrityAuditTestBase - .setUpBeforeClass(DEFAULT_DB_URL_PREFIX + DbAuditCompareEntriesTest.class.getSimpleName()); - } - - @AfterClass - public static void tearDownAfterClass() { - IntegrityAuditTestBase.tearDownAfterClass(); - } - - @Before - public void setUp() { - - logger.info("setUp: Entering"); - - super.setUp(); - - truncateTables(makeProperties()); - - logger.info("setUp: Exiting"); - } - - /* - * Clean up DB after each test. - */ - @After - public void tearDown() { - logger.info("tearDown: Entering"); - - dbDAO.destroy(); - - super.tearDown(); - - logger.info("tearDown: Exiting"); - } - - /* - * Tests that a comparison between hashsets is successful if the entries - * match - */ - // @Ignore - @Test - public void testSuccessfulComparison() throws Exception { - logger.info("testSuccessfulComparison: Entering"); - - dbDAO = new DbDAO(resourceName, A_SEQ_PU, makeProperties()); - DbAudit dbAudit = new DbAudit(dbDAO); - - String className = null; - // There is only one entry IntegrityAuditEntity, but we will check - // anyway - Set<String> classNameSet = dbDAO.getPersistenceClassNames(); - for (String c : classNameSet) { - if (c.equals("org.onap.policy.common.ia.jpa.IntegrityAuditEntity")) { - className = c; - } - } - String resourceName1 = resourceName; - String resourceName2 = resourceName; - - IntegrityAuditEntity entry1 = new IntegrityAuditEntity(); - IntegrityAuditEntity entry2 = new IntegrityAuditEntity(); - Date date = new Date(); - - /* - * Two entries with the same field values - */ - entry1.setDesignated(false); - entry1.setJdbcDriver(dbDriver); - entry1.setJdbcPassword(dbPwd); - entry1.setJdbcUrl(dbUrl); - entry1.setJdbcUser(dbUser); - entry1.setLastUpdated(date); - entry1.setNodeType(nodeType); - entry1.setPersistenceUnit(A_SEQ_PU); - entry1.setResourceName(resourceName1); - entry1.setSite(siteName); - - entry2.setDesignated(false); - entry2.setJdbcDriver(dbDriver); - entry2.setJdbcPassword(dbPwd); - entry2.setJdbcUrl(dbUrl); - entry2.setJdbcUser(dbUser); - entry2.setLastUpdated(date); - entry2.setNodeType(nodeType); - entry2.setPersistenceUnit(A_SEQ_PU); - entry2.setResourceName(resourceName2); - entry2.setSite(siteName); - - dbAudit.writeAuditDebugLog(className, resourceName1, resourceName2, entry1, entry2); - - HashMap<Object, Object> myEntries = new HashMap<Object, Object>(); - HashMap<Object, Object> theirEntries = new HashMap<Object, Object>(); - - myEntries.put("pdp1", entry1); - theirEntries.put("pdp1", entry2); - - Set<Object> result = dbAudit.compareEntries(myEntries, theirEntries); - - /* - * Assert that there are no mismatches returned - */ - assertTrue(result.isEmpty()); - - logger.info("testSuccessfulComparison: Exit"); - } - - /* - * Tests that an error is detected if an entry in one hashset doesn't match - * the other - */ - // @Ignore - @Test - public void testComparisonError() throws Exception { - logger.info("testComparisonError: Entering"); - - dbDAO = new DbDAO(resourceName, A_SEQ_PU, makeProperties()); - DbAudit dbAudit = new DbAudit(dbDAO); - - String resourceName1 = resourceName; - String resourceName2 = resourceName; - - IntegrityAuditEntity entry1 = new IntegrityAuditEntity(); - IntegrityAuditEntity entry2 = new IntegrityAuditEntity(); - Date date = new Date(); - - /* - * Create two entries with different designated values - */ - entry1.setDesignated(false); - entry1.setJdbcDriver(dbDriver); - entry1.setJdbcPassword(dbPwd); - entry1.setJdbcUrl(dbUrl); - entry1.setJdbcUser(dbUser); - entry1.setLastUpdated(date); - entry1.setNodeType(nodeType); - entry1.setPersistenceUnit(A_SEQ_PU); - entry1.setResourceName(resourceName1); - entry1.setSite(siteName); - - entry2.setDesignated(true); - entry2.setJdbcDriver(dbDriver); - entry2.setJdbcPassword(dbPwd); - entry2.setJdbcUrl(dbUrl); - entry2.setJdbcUser(dbUser); - entry2.setLastUpdated(date); - entry2.setNodeType(nodeType); - entry2.setPersistenceUnit(A_SEQ_PU); - entry2.setResourceName(resourceName2); - entry2.setSite(siteName); - - HashMap<Object, Object> myEntries = new HashMap<Object, Object>(); - HashMap<Object, Object> theirEntries = new HashMap<Object, Object>(); - - myEntries.put("pdp1", entry1); - theirEntries.put("pdp1", entry2); - - Set<Object> result = dbAudit.compareEntries(myEntries, theirEntries); - - /* - * Assert that there was one mismatch - */ - assertEquals(1, result.size()); - - logger.info("testComparisonError: Exit"); - } - - /* - * Tests that a mismatch/miss entry is detected if there are missing entries - * in one or both of the hashsets - */ - // @Ignore - @Test - public void testCompareMissingEntries() throws Exception { - logger.info("testCompareMissingEntries: Entering"); - - dbDAO = new DbDAO(resourceName, A_SEQ_PU, makeProperties()); - DbAudit dbAudit = new DbAudit(dbDAO); - - String resourceName1 = resourceName; - String resourceName2 = resourceName; - - IntegrityAuditEntity entry1 = new IntegrityAuditEntity(); - IntegrityAuditEntity entry2 = new IntegrityAuditEntity(); - IntegrityAuditEntity entry3 = new IntegrityAuditEntity(); - IntegrityAuditEntity entry4 = new IntegrityAuditEntity(); - - Date date = new Date(); - - /* - * 4 entries, one mismatch, two miss entries - */ - entry1.setDesignated(false); - entry1.setJdbcDriver(dbDriver); - entry1.setJdbcPassword(dbPwd); - entry1.setJdbcUrl(dbUrl); - entry1.setJdbcUser(dbUser); - entry1.setLastUpdated(date); - entry1.setNodeType(nodeType); - entry1.setPersistenceUnit(A_SEQ_PU); - entry1.setResourceName(resourceName1); - entry1.setSite(siteName); - - entry2.setDesignated(true); - entry2.setJdbcDriver(dbDriver); - entry2.setJdbcPassword(dbPwd); - entry2.setJdbcUrl(dbUrl); - entry2.setJdbcUser(dbUser); - entry2.setLastUpdated(date); - entry2.setNodeType(nodeType); - entry2.setPersistenceUnit(A_SEQ_PU); - entry2.setResourceName(resourceName2); - entry2.setSite(siteName); - - entry3.setDesignated(false); - entry3.setJdbcDriver(dbDriver); - entry3.setJdbcPassword(dbPwd); - entry3.setJdbcUrl(dbUrl); - entry3.setJdbcUser(dbUser); - entry3.setLastUpdated(date); - entry3.setNodeType(nodeType); - entry3.setPersistenceUnit(A_SEQ_PU); - entry3.setResourceName(resourceName2); - entry3.setSite("SiteB"); - - entry4.setDesignated(false); - entry4.setJdbcDriver(dbDriver); - entry4.setJdbcPassword(dbPwd); - entry4.setJdbcUrl(dbUrl); - entry4.setJdbcUser(dbUser); - entry4.setLastUpdated(date); - entry4.setNodeType(nodeType); - entry4.setPersistenceUnit(A_SEQ_PU); - entry4.setResourceName(resourceName2); - entry4.setSite("SiteB"); - - HashMap<Object, Object> myEntries = new HashMap<Object, Object>(); - HashMap<Object, Object> theirEntries = new HashMap<Object, Object>(); - - myEntries.put("0", entry1); - myEntries.put("1", entry3); - theirEntries.put("0", entry2); - theirEntries.put("2", entry4); - - Set<Object> mismatchResult = dbAudit.compareEntries(myEntries, theirEntries); - - /* - * Assert 3 mismatches/missing entries were found - */ - assertEquals(3, mismatchResult.size()); - - logger.info("testCompareMissingEntries: Exit"); - } - - /* - * Tests that comparison algorithm works for each entity in the hashsets - */ - // @Ignore - @Test - public void testCompareAllHashEntities() throws Exception { - logger.info("testCompareAllHashEntities: Entering"); - - dbDAO = new DbDAO(resourceName, A_SEQ_PU, makeProperties()); - DbAudit dbAudit = new DbAudit(dbDAO); - - Set<String> classNameSet = dbDAO.getPersistenceClassNames(); - Set<Object> mismatchResult = new HashSet<Object>(); - for (String c : classNameSet) { - if (c.equals("org.onap.policy.common.ia.jpa.IntegrityAuditEntity")) { - String resourceName1 = resourceName; - String resourceName2 = resourceName; - - IntegrityAuditEntity entry1 = new IntegrityAuditEntity(); - IntegrityAuditEntity entry2 = new IntegrityAuditEntity(); - Date date = new Date(); - - /* - * Two entries with the same field values - */ - entry1.setDesignated(false); - entry1.setJdbcDriver(dbDriver); - entry1.setJdbcPassword(dbPwd); - entry1.setJdbcUrl(dbUrl); - entry1.setJdbcUser(dbUser); - entry1.setLastUpdated(date); - entry1.setNodeType(nodeType); - entry1.setPersistenceUnit(A_SEQ_PU); - entry1.setResourceName(resourceName1); - entry1.setSite(siteName); - - entry2.setDesignated(false); - entry2.setJdbcDriver(dbDriver); - entry2.setJdbcPassword(dbPwd); - entry2.setJdbcUrl(dbUrl); - entry2.setJdbcUser(dbUser); - entry2.setLastUpdated(date); - entry2.setNodeType(nodeType); - entry2.setPersistenceUnit(A_SEQ_PU); - entry2.setResourceName(resourceName2); - entry2.setSite(siteName); - - HashMap<Object, Object> myEntries = new HashMap<Object, Object>(); - HashMap<Object, Object> theirEntries = new HashMap<Object, Object>(); - - myEntries.put("pdp1", entry1); - theirEntries.put("pdp1", entry2); - - mismatchResult = dbAudit.compareEntries(myEntries, theirEntries); - - /* - * Assert there was no mismatches - */ - assertTrue(mismatchResult.isEmpty()); - } else if (c.equals("org.onap.policy.common.ia.jpa.IaTestEntity")) { - IaTestEntity iate = new IaTestEntity(); - IaTestEntity iate2 = new IaTestEntity(); - IaTestEntity iate3 = new IaTestEntity(); - IaTestEntity iate4 = new IaTestEntity(); - - Date date = new Date(); - - /* - * Four entries, 2 mismatches - */ - iate.setCreatedBy("Ford"); - iate.setModifiedBy("Ford"); - iate.setModifiedDate(date); - - iate2.setCreatedBy("Ford"); - iate2.setModifiedBy("Zaphod"); - iate2.setModifiedDate(date); - - iate3.setCreatedBy("Zaphod"); - iate3.setModifiedBy("Ford"); - iate3.setModifiedDate(date); - - iate4.setCreatedBy("Ford"); - iate4.setModifiedBy("Ford"); - iate4.setModifiedDate(date); - - HashMap<Object, Object> myEntries = new HashMap<Object, Object>(); - HashMap<Object, Object> theirEntries = new HashMap<Object, Object>(); - - myEntries.put("0", iate); - myEntries.put("1", iate2); - theirEntries.put("0", iate3); - theirEntries.put("1", iate4); - - mismatchResult = dbAudit.compareEntries(myEntries, theirEntries); - - /* - * Assert that there is 2 mismatches - */ - assertEquals(2, mismatchResult.size()); - } - } - - logger.info("testCompareAllHashEntities: Exit"); - } - - /* - * Tests that comparison algorithm works for each entity in the database - */ - @Ignore - @Test - public void testCompareAllDbEntities() throws Exception { - logger.info("testCompareAllDbEntities: Entering"); - - logger.info("Setting up DB"); - - IntegrityAudit.setUnitTesting(true); - - Properties properties = makeProperties(); - - Properties properties2 = makeProperties(); - properties2.put(IntegrityAuditProperties.DB_URL, - "jdbc:h2:mem:" + DbAuditCompareEntriesTest.class.getSimpleName() + "2"); - - // Clean up the two DBs - truncateTables(properties); - truncateTables(properties2); - - // Add entries into DB1 - dbDAO = new DbDAO(resourceName, A_SEQ_PU, properties); - new DbDAO("pdp2", A_SEQ_PU, properties).destroy(); - DbAudit dbAudit = new DbAudit(dbDAO); - - // Add entries into DB2 - DbDAO dbDAO3 = new DbDAO(resourceName, A_SEQ_PU, properties2); - new DbDAO("pdp2", A_SEQ_PU, properties2).destroy(); - - // Pull all entries and compare - Set<String> classNameSet = dbDAO.getPersistenceClassNames(); - Map<Object, Object> myEntries; - Map<Object, Object> theirEntries; - Set<Object> mismatchResult = new HashSet<Object>(); - String className; - for (String c : classNameSet) { - className = c; - logger.info("classNameSet entry = " + c); - myEntries = dbDAO.getAllEntries(A_SEQ_PU, properties, className); - theirEntries = dbDAO3.getAllEntries(A_SEQ_PU, properties2, className); - mismatchResult = dbAudit.compareEntries(myEntries, theirEntries); - if (className.contains("IntegrityAuditEntity")) { - break; - } - } - - dbDAO3.destroy(); - - // Assert that there is 2 mismatches between IntegrityAuditEntity tables - assertEquals(2, mismatchResult.size()); - - logger.info("testCompareAllDbEntities: Exit"); - } - - /** - * @param properties - */ - private void truncateTables(Properties properties) { - truncateTable(properties, A_SEQ_PU, "IntegrityAuditEntity"); - truncateTable(properties, A_SEQ_PU, "IaTestEntity"); - } - - /* - * Tests that differences in embedded classes are still caught - */ - // @Ignore - @Test - public void testEmbeddedClass() throws Exception { - logger.info("testEmbeddedClasses: Entering"); - - dbDAO = new DbDAO(resourceName, A_SEQ_PU, properties); - DbAudit dbAudit = new DbAudit(dbDAO); - - String className = null; - // There is only one entry IntegrityAuditEntity, but we will check - // anyway - Set<String> classNameSet = dbDAO.getPersistenceClassNames(); - for (String c : classNameSet) { - if (c.equals("org.onap.policy.common.ia.jpa.IaTestEntity")) { - className = c; - } - } - - IaTestEntity iate = new IaTestEntity(); - IaTestEntity iate2 = new IaTestEntity(); - - Date date = new Date(); - - PersonSample person = new PersonSample("Ford", "Prefect", 21); - PersonSample person2 = new PersonSample("Zaphod", "Beeblebrox", 25); - - /* - * Silly tests to bump coverage stats, not sure why they are counting - * PersonSample to begin with. Will have to look into that at some - * point. - */ - assertNotEquals(person.getAge(), person2.getAge()); - assertNotEquals(person.getFirstName(), person2.getFirstName()); - assertNotEquals(person.getLasttName(), person2.getLasttName()); - PersonSample personTest = new PersonSample(null, null, 0); - personTest.setAge(person.getAge()); - personTest.setFirstName(person.getFirstName()); - personTest.setLastName(person.getLasttName()); - /* - * Two entries, 1 mismatch - */ - iate.setCreatedBy("Ford"); - iate.setModifiedBy("Zaphod"); - iate.setModifiedDate(date); - iate.setPersonTest(person); - - iate2.setCreatedBy("Ford"); - iate2.setModifiedBy("Zaphod"); - iate2.setModifiedDate(date); - iate2.setPersonTest(person2); - - dbAudit.writeAuditDebugLog(className, "resource1", "resource2", iate, iate2); - - HashMap<Object, Object> myEntries = new HashMap<Object, Object>(); - HashMap<Object, Object> theirEntries = new HashMap<Object, Object>(); - - myEntries.put("0", iate); - theirEntries.put("0", iate2); - - Set<Object> result = dbAudit.compareEntries(myEntries, theirEntries); - - /* - * Assert that there are no mismatches returned - */ - assertTrue(!result.isEmpty()); - - logger.info("testEmbeddedClasses: Exit"); - } + private static Logger logger = FlexLogger.getLogger(DbAuditCompareEntriesTest.class); + + private DbDAO dbDao; + private static String resourceName = "pdp1"; + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + IntegrityAuditTestBase + .setUpBeforeClass(DEFAULT_DB_URL_PREFIX + DbAuditCompareEntriesTest.class.getSimpleName()); + } + + @AfterClass + public static void tearDownAfterClass() { + IntegrityAuditTestBase.tearDownAfterClass(); + } + + /** + * Set up for test cases. + */ + @Override + @Before + public void setUp() { + + logger.info("setUp: Entering"); + + super.setUp(); + + truncateTables(makeProperties()); + + logger.info("setUp: Exiting"); + } + + /** + * Clean up DB after each test. + */ + @Override + @After + public void tearDown() { + logger.info("tearDown: Entering"); + + dbDao.destroy(); + + super.tearDown(); + + logger.info("tearDown: Exiting"); + } + + /* + * Tests that a comparison between hashsets is successful if the entries match + */ + // @Ignore + @Test + public void testSuccessfulComparison() throws Exception { + logger.info("testSuccessfulComparison: Entering"); + + dbDao = new DbDAO(resourceName, A_SEQ_PU, makeProperties()); + final DbAudit dbAudit = new DbAudit(dbDao); + + String className = null; + // There is only one entry IntegrityAuditEntity, but we will check + // anyway + Set<String> classNameSet = dbDao.getPersistenceClassNames(); + for (String c : classNameSet) { + if (c.equals("org.onap.policy.common.ia.jpa.IntegrityAuditEntity")) { + className = c; + } + } + final String resourceName1 = resourceName; + final String resourceName2 = resourceName; + + final IntegrityAuditEntity entry1 = new IntegrityAuditEntity(); + final IntegrityAuditEntity entry2 = new IntegrityAuditEntity(); + Date date = new Date(); + + /* + * Two entries with the same field values + */ + entry1.setDesignated(false); + entry1.setJdbcDriver(dbDriver); + entry1.setJdbcPassword(dbPwd); + entry1.setJdbcUrl(dbUrl); + entry1.setJdbcUser(dbUser); + entry1.setLastUpdated(date); + entry1.setNodeType(nodeType); + entry1.setPersistenceUnit(A_SEQ_PU); + entry1.setResourceName(resourceName1); + entry1.setSite(siteName); + + entry2.setDesignated(false); + entry2.setJdbcDriver(dbDriver); + entry2.setJdbcPassword(dbPwd); + entry2.setJdbcUrl(dbUrl); + entry2.setJdbcUser(dbUser); + entry2.setLastUpdated(date); + entry2.setNodeType(nodeType); + entry2.setPersistenceUnit(A_SEQ_PU); + entry2.setResourceName(resourceName2); + entry2.setSite(siteName); + + dbAudit.writeAuditDebugLog(className, resourceName1, resourceName2, entry1, entry2); + + HashMap<Object, Object> myEntries = new HashMap<Object, Object>(); + HashMap<Object, Object> theirEntries = new HashMap<Object, Object>(); + + myEntries.put("pdp1", entry1); + theirEntries.put("pdp1", entry2); + + Set<Object> result = dbAudit.compareEntries(myEntries, theirEntries); + + /* + * Assert that there are no mismatches returned + */ + assertTrue(result.isEmpty()); + + logger.info("testSuccessfulComparison: Exit"); + } + + /* + * Tests that an error is detected if an entry in one hashset doesn't match the other + */ + // @Ignore + @Test + public void testComparisonError() throws Exception { + logger.info("testComparisonError: Entering"); + + dbDao = new DbDAO(resourceName, A_SEQ_PU, makeProperties()); + final DbAudit dbAudit = new DbAudit(dbDao); + + final String resourceName1 = resourceName; + final String resourceName2 = resourceName; + + final IntegrityAuditEntity entry1 = new IntegrityAuditEntity(); + final IntegrityAuditEntity entry2 = new IntegrityAuditEntity(); + Date date = new Date(); + + /* + * Create two entries with different designated values + */ + entry1.setDesignated(false); + entry1.setJdbcDriver(dbDriver); + entry1.setJdbcPassword(dbPwd); + entry1.setJdbcUrl(dbUrl); + entry1.setJdbcUser(dbUser); + entry1.setLastUpdated(date); + entry1.setNodeType(nodeType); + entry1.setPersistenceUnit(A_SEQ_PU); + entry1.setResourceName(resourceName1); + entry1.setSite(siteName); + + entry2.setDesignated(true); + entry2.setJdbcDriver(dbDriver); + entry2.setJdbcPassword(dbPwd); + entry2.setJdbcUrl(dbUrl); + entry2.setJdbcUser(dbUser); + entry2.setLastUpdated(date); + entry2.setNodeType(nodeType); + entry2.setPersistenceUnit(A_SEQ_PU); + entry2.setResourceName(resourceName2); + entry2.setSite(siteName); + + HashMap<Object, Object> myEntries = new HashMap<Object, Object>(); + HashMap<Object, Object> theirEntries = new HashMap<Object, Object>(); + + myEntries.put("pdp1", entry1); + theirEntries.put("pdp1", entry2); + + Set<Object> result = dbAudit.compareEntries(myEntries, theirEntries); + + /* + * Assert that there was one mismatch + */ + assertEquals(1, result.size()); + + logger.info("testComparisonError: Exit"); + } + + /* + * Tests that a mismatch/miss entry is detected if there are missing entries in one or both of + * the hashsets + */ + // @Ignore + @Test + public void testCompareMissingEntries() throws Exception { + logger.info("testCompareMissingEntries: Entering"); + + dbDao = new DbDAO(resourceName, A_SEQ_PU, makeProperties()); + final DbAudit dbAudit = new DbAudit(dbDao); + + final String resourceName1 = resourceName; + final String resourceName2 = resourceName; + + final IntegrityAuditEntity entry1 = new IntegrityAuditEntity(); + final IntegrityAuditEntity entry2 = new IntegrityAuditEntity(); + final IntegrityAuditEntity entry3 = new IntegrityAuditEntity(); + final IntegrityAuditEntity entry4 = new IntegrityAuditEntity(); + + Date date = new Date(); + + /* + * 4 entries, one mismatch, two miss entries + */ + entry1.setDesignated(false); + entry1.setJdbcDriver(dbDriver); + entry1.setJdbcPassword(dbPwd); + entry1.setJdbcUrl(dbUrl); + entry1.setJdbcUser(dbUser); + entry1.setLastUpdated(date); + entry1.setNodeType(nodeType); + entry1.setPersistenceUnit(A_SEQ_PU); + entry1.setResourceName(resourceName1); + entry1.setSite(siteName); + + entry2.setDesignated(true); + entry2.setJdbcDriver(dbDriver); + entry2.setJdbcPassword(dbPwd); + entry2.setJdbcUrl(dbUrl); + entry2.setJdbcUser(dbUser); + entry2.setLastUpdated(date); + entry2.setNodeType(nodeType); + entry2.setPersistenceUnit(A_SEQ_PU); + entry2.setResourceName(resourceName2); + entry2.setSite(siteName); + + entry3.setDesignated(false); + entry3.setJdbcDriver(dbDriver); + entry3.setJdbcPassword(dbPwd); + entry3.setJdbcUrl(dbUrl); + entry3.setJdbcUser(dbUser); + entry3.setLastUpdated(date); + entry3.setNodeType(nodeType); + entry3.setPersistenceUnit(A_SEQ_PU); + entry3.setResourceName(resourceName2); + entry3.setSite("SiteB"); + + entry4.setDesignated(false); + entry4.setJdbcDriver(dbDriver); + entry4.setJdbcPassword(dbPwd); + entry4.setJdbcUrl(dbUrl); + entry4.setJdbcUser(dbUser); + entry4.setLastUpdated(date); + entry4.setNodeType(nodeType); + entry4.setPersistenceUnit(A_SEQ_PU); + entry4.setResourceName(resourceName2); + entry4.setSite("SiteB"); + + HashMap<Object, Object> myEntries = new HashMap<Object, Object>(); + HashMap<Object, Object> theirEntries = new HashMap<Object, Object>(); + + myEntries.put("0", entry1); + myEntries.put("1", entry3); + theirEntries.put("0", entry2); + theirEntries.put("2", entry4); + + Set<Object> mismatchResult = dbAudit.compareEntries(myEntries, theirEntries); + + /* + * Assert 3 mismatches/missing entries were found + */ + assertEquals(3, mismatchResult.size()); + + logger.info("testCompareMissingEntries: Exit"); + } + + /* + * Tests that comparison algorithm works for each entity in the hashsets + */ + // @Ignore + @Test + public void testCompareAllHashEntities() throws Exception { + logger.info("testCompareAllHashEntities: Entering"); + + dbDao = new DbDAO(resourceName, A_SEQ_PU, makeProperties()); + DbAudit dbAudit = new DbAudit(dbDao); + + Set<String> classNameSet = dbDao.getPersistenceClassNames(); + Set<Object> mismatchResult = new HashSet<Object>(); + for (String className : classNameSet) { + if (className.equals("org.onap.policy.common.ia.jpa.IntegrityAuditEntity")) { + final String resourceName1 = resourceName; + final String resourceName2 = resourceName; + + final IntegrityAuditEntity entry1 = new IntegrityAuditEntity(); + final IntegrityAuditEntity entry2 = new IntegrityAuditEntity(); + Date date = new Date(); + + /* + * Two entries with the same field values + */ + entry1.setDesignated(false); + entry1.setJdbcDriver(dbDriver); + entry1.setJdbcPassword(dbPwd); + entry1.setJdbcUrl(dbUrl); + entry1.setJdbcUser(dbUser); + entry1.setLastUpdated(date); + entry1.setNodeType(nodeType); + entry1.setPersistenceUnit(A_SEQ_PU); + entry1.setResourceName(resourceName1); + entry1.setSite(siteName); + + entry2.setDesignated(false); + entry2.setJdbcDriver(dbDriver); + entry2.setJdbcPassword(dbPwd); + entry2.setJdbcUrl(dbUrl); + entry2.setJdbcUser(dbUser); + entry2.setLastUpdated(date); + entry2.setNodeType(nodeType); + entry2.setPersistenceUnit(A_SEQ_PU); + entry2.setResourceName(resourceName2); + entry2.setSite(siteName); + + HashMap<Object, Object> myEntries = new HashMap<Object, Object>(); + HashMap<Object, Object> theirEntries = new HashMap<Object, Object>(); + + myEntries.put("pdp1", entry1); + theirEntries.put("pdp1", entry2); + + mismatchResult = dbAudit.compareEntries(myEntries, theirEntries); + + /* + * Assert there was no mismatches + */ + assertTrue(mismatchResult.isEmpty()); + } else if (className.equals("org.onap.policy.common.ia.jpa.IaTestEntity")) { + final IaTestEntity iate = new IaTestEntity(); + final IaTestEntity iate2 = new IaTestEntity(); + final IaTestEntity iate3 = new IaTestEntity(); + final IaTestEntity iate4 = new IaTestEntity(); + + Date date = new Date(); + + /* + * Four entries, 2 mismatches + */ + iate.setCreatedBy("Ford"); + iate.setModifiedBy("Ford"); + iate.setModifiedDate(date); + + iate2.setCreatedBy("Ford"); + iate2.setModifiedBy("Zaphod"); + iate2.setModifiedDate(date); + + iate3.setCreatedBy("Zaphod"); + iate3.setModifiedBy("Ford"); + iate3.setModifiedDate(date); + + iate4.setCreatedBy("Ford"); + iate4.setModifiedBy("Ford"); + iate4.setModifiedDate(date); + + HashMap<Object, Object> myEntries = new HashMap<Object, Object>(); + HashMap<Object, Object> theirEntries = new HashMap<Object, Object>(); + + myEntries.put("0", iate); + myEntries.put("1", iate2); + theirEntries.put("0", iate3); + theirEntries.put("1", iate4); + + mismatchResult = dbAudit.compareEntries(myEntries, theirEntries); + + /* + * Assert that there is 2 mismatches + */ + assertEquals(2, mismatchResult.size()); + } + } + + logger.info("testCompareAllHashEntities: Exit"); + } + + /* + * Tests that comparison algorithm works for each entity in the database + */ + @Ignore + @Test + public void testCompareAllDbEntities() throws Exception { + logger.info("testCompareAllDbEntities: Entering"); + + logger.info("Setting up DB"); + + IntegrityAudit.setUnitTesting(true); + + Properties properties = makeProperties(); + + Properties properties2 = makeProperties(); + properties2.put(IntegrityAuditProperties.DB_URL, + "jdbc:h2:mem:" + DbAuditCompareEntriesTest.class.getSimpleName() + "2"); + + // Clean up the two DBs + truncateTables(properties); + truncateTables(properties2); + + // Add entries into DB1 + dbDao = new DbDAO(resourceName, A_SEQ_PU, properties); + new DbDAO("pdp2", A_SEQ_PU, properties).destroy(); + DbAudit dbAudit = new DbAudit(dbDao); + + // Add entries into DB2 + DbDAO dbDao3 = new DbDAO(resourceName, A_SEQ_PU, properties2); + new DbDAO("pdp2", A_SEQ_PU, properties2).destroy(); + + // Pull all entries and compare + Set<String> classNameSet = dbDao.getPersistenceClassNames(); + Map<Object, Object> myEntries; + Map<Object, Object> theirEntries; + Set<Object> mismatchResult = new HashSet<Object>(); + for (String className : classNameSet) { + logger.info("classNameSet entry = " + className); + myEntries = dbDao.getAllEntries(A_SEQ_PU, properties, className); + theirEntries = dbDao3.getAllEntries(A_SEQ_PU, properties2, className); + mismatchResult = dbAudit.compareEntries(myEntries, theirEntries); + if (className.contains("IntegrityAuditEntity")) { + break; + } + } + + dbDao3.destroy(); + + // Assert that there is 2 mismatches between IntegrityAuditEntity tables + assertEquals(2, mismatchResult.size()); + + logger.info("testCompareAllDbEntities: Exit"); + } + + /** + * Truncate the tables. + * + * @param properties the properties + */ + private void truncateTables(Properties properties) { + truncateTable(properties, A_SEQ_PU, "IntegrityAuditEntity"); + truncateTable(properties, A_SEQ_PU, "IaTestEntity"); + } + + /* + * Tests that differences in embedded classes are still caught + */ + // @Ignore + @Test + public void testEmbeddedClass() throws Exception { + logger.info("testEmbeddedClasses: Entering"); + + dbDao = new DbDAO(resourceName, A_SEQ_PU, properties); + final DbAudit dbAudit = new DbAudit(dbDao); + + String className = null; + // There is only one entry IntegrityAuditEntity, but we will check + // anyway + Set<String> classNameSet = dbDao.getPersistenceClassNames(); + for (String classNameInClassNameSet : classNameSet) { + if (classNameInClassNameSet.equals("org.onap.policy.common.ia.jpa.IaTestEntity")) { + className = classNameInClassNameSet; + } + } + + final IaTestEntity iate = new IaTestEntity(); + final IaTestEntity iate2 = new IaTestEntity(); + + final Date date = new Date(); + + PersonSample person = new PersonSample("Ford", "Prefect", 21); + PersonSample person2 = new PersonSample("Zaphod", "Beeblebrox", 25); + + /* + * Silly tests to bump coverage stats, not sure why they are counting PersonSample to begin + * with. Will have to look into that at some point. + */ + assertNotEquals(person.getAge(), person2.getAge()); + assertNotEquals(person.getFirstName(), person2.getFirstName()); + assertNotEquals(person.getLasttName(), person2.getLasttName()); + PersonSample personTest = new PersonSample(null, null, 0); + personTest.setAge(person.getAge()); + personTest.setFirstName(person.getFirstName()); + personTest.setLastName(person.getLasttName()); + /* + * Two entries, 1 mismatch + */ + iate.setCreatedBy("Ford"); + iate.setModifiedBy("Zaphod"); + iate.setModifiedDate(date); + iate.setPersonTest(person); + + iate2.setCreatedBy("Ford"); + iate2.setModifiedBy("Zaphod"); + iate2.setModifiedDate(date); + iate2.setPersonTest(person2); + + dbAudit.writeAuditDebugLog(className, "resource1", "resource2", iate, iate2); + + HashMap<Object, Object> myEntries = new HashMap<Object, Object>(); + HashMap<Object, Object> theirEntries = new HashMap<Object, Object>(); + + myEntries.put("0", iate); + theirEntries.put("0", iate2); + + Set<Object> result = dbAudit.compareEntries(myEntries, theirEntries); + + /* + * Assert that there are no mismatches returned + */ + assertTrue(!result.isEmpty()); + + logger.info("testEmbeddedClasses: Exit"); + } } diff --git a/integrity-audit/src/test/java/org/onap/policy/common/ia/DbAuditTest.java b/integrity-audit/src/test/java/org/onap/policy/common/ia/DbAuditTest.java index ad4041f5..cfbf90cb 100644 --- a/integrity-audit/src/test/java/org/onap/policy/common/ia/DbAuditTest.java +++ b/integrity-audit/src/test/java/org/onap/policy/common/ia/DbAuditTest.java @@ -53,230 +53,236 @@ import org.onap.policy.common.utils.test.log.logback.ExtractAppender; */ public class DbAuditTest extends IntegrityAuditTestBase { - private static Logger logger = FlexLogger.getLogger(DbAuditTest.class); + private static Logger logger = FlexLogger.getLogger(DbAuditTest.class); + + private static final String resourceName = "pdp1"; + + private EntityManagerFactory emf2; + private EntityManager em2; + private DbDAO dbDao; + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + IntegrityAuditTestBase.setUpBeforeClass(DEFAULT_DB_URL_PREFIX + DbAuditTest.class.getSimpleName()); + IntegrityAuditEntity.setUnitTesting(true); + } + + @AfterClass + public static void tearDownAfterClass() { + IntegrityAuditTestBase.tearDownAfterClass(); + IntegrityAuditEntity.setUnitTesting(false); + } + + /** + * Set up for test cases. + */ + @Override + @Before + public void setUp() { + logger.info("setUp: Entering"); + + super.setUp(); + + dbDao = null; + emf2 = null; + em2 = null; + + logger.info("setUp: Exiting"); + } + + /** + * Tear down after test cases. + */ + @Override + @After + public void tearDown() { + logger.info("tearDown: Entering"); + + if (dbDao != null) { + dbDao.destroy(); + } + + if (em2 != null) { + em2.close(); + } + + if (emf2 != null) { + emf2.close(); + } + + super.tearDown(); - private static final String resourceName = "pdp1"; + logger.info("tearDown: Exiting"); + } + + private void createDb(Properties properties) { + if (emf2 != null) { + throw new IllegalStateException("DB2 has already been created"); + } + + // open the DB and ensure it stays open until the test completes + emf2 = Persistence.createEntityManagerFactory(A_SEQ_PU, properties); + em2 = emf2.createEntityManager(); + + truncateTable(properties, A_SEQ_PU, "IntegrityAuditEntity"); + } + + /* + * Tests printing an error to the log in the event where there are no entities saved in the + * database + */ + @Test + public void noEntitiesTest() throws Exception { + Properties properties = makeProperties(); + + logger.info("noEntitiesTest: Entering"); + + dbDao = new DbDAO(resourceName, A_SEQ_PU, properties); + dbDao.deleteAllIntegrityAuditEntities(); + try { + DbAudit dbAudit = new DbAudit(dbDao); + dbAudit.dbAudit(resourceName, A_SEQ_PU, nodeType); + fail("found unexpected entities"); + + } catch (DbAuditException e) { + // Ignore expected exception + } + + logger.info("noEntitiesTest: Exit"); + } + + /* + * Tests the detection of only one entry in the database + */ + @Test + public void oneEntityTest() throws Exception { + Properties properties = makeProperties(); + + logger.info("oneEntityTest: Entering"); + + final ExtractAppender log = watch(debugLogger, "DbAudit: Found only (one) IntegrityAuditEntity entry:"); + + // Add one entry in the database + dbDao = new DbDAO(resourceName, A_SEQ_PU, properties); + DbAudit dbAudit = new DbAudit(dbDao); + dbAudit.dbAudit(resourceName, A_SEQ_PU, nodeType); + + List<IntegrityAuditEntity> iaeList = dbDao.getIntegrityAuditEntities(A_SEQ_PU, nodeType); + logger.info("List size: " + iaeList.size()); + + verifyItemsInLog(log, "one"); + + logger.info("oneEntityTest: Exit"); + } + + /* + * Tests reporting mismatches and missing entries using the error log + */ + @Test + public void mismatchTest() throws Exception { + logger.info("mismatchTest: Entering"); + + // use new URLs so we get a completely new DB + String dbUrl = DbAuditTest.dbUrl + "_mismatchTest"; + String dbUrl2 = dbUrl + "2"; + + Properties properties = makeProperties(); + properties.put(IntegrityAuditProperties.DB_URL, dbUrl); + + // Properties for DB2 + Properties properties2 = makeProperties(); + properties2.put(IntegrityAuditProperties.DB_URL, dbUrl2); + + /* + * We must drop and re-create DB1 so that it's sequence generator is in step with the + * sequence generator for DB2. + */ + recreateDb1(properties); + + // create/open DB2 + createDb(properties2); - private EntityManagerFactory emf2; - private EntityManager em2; - private DbDAO dbDAO; + final ExtractAppender dbglog = watch(debugLogger, "Mismatched entries [(]keys[)]:(.*)"); + final ExtractAppender errlog = watch(errorLogger, "DB Audit: ([0-9])"); + + /* + * Create entries in DB1 & DB2 for the resource of interest + */ + dbDao = new DbDAO(resourceName, A_SEQ_PU, properties); - @BeforeClass - public static void setUpBeforeClass() throws Exception { - IntegrityAuditTestBase.setUpBeforeClass(DEFAULT_DB_URL_PREFIX + DbAuditTest.class.getSimpleName()); - IntegrityAuditEntity.setUnitTesting(true); - } + new DbDAO(resourceName, A_SEQ_PU, properties2).destroy(); + + /* + * Entries in DB1, pointing to DB2, except for pdp3 + */ + new DbDAO("pdp2", A_SEQ_PU, properties, dbUrl2).destroy(); + new DbDAO("pdp1", A_SEQ_PU, properties, dbUrl2).destroy(); + new DbDAO("pdp3", A_SEQ_PU, properties).destroy(); // mismatched URL + new DbDAO("pdp4", A_SEQ_PU, properties, dbUrl2).destroy(); + + /* + * Identical entries in DB2, all pointing to DB2, including pdp3, but leaving out pdp4 + */ + new DbDAO("pdp2", A_SEQ_PU, properties2).destroy(); + new DbDAO("pdp1", A_SEQ_PU, properties2).destroy(); + new DbDAO("pdp3", A_SEQ_PU, properties2).destroy(); + + /* + * Run the DB Audit, once it finds a mismatch and sleeps, update DB1 to have the same entry + * as DB2 it can be confirmed that the mismatch is resolved + */ + DbAudit dbAudit = new DbAudit(dbDao); + dbAudit.dbAudit(resourceName, A_SEQ_PU, nodeType); - @AfterClass - public static void tearDownAfterClass() { - IntegrityAuditTestBase.tearDownAfterClass(); - IntegrityAuditEntity.setUnitTesting(false); - } + // update pdp3 entry in DB1 to point to DB2 + new DbDAO("pdp3", A_SEQ_PU, properties, dbUrl2).destroy(); + + /* + * Run the audit again and correct the mismatch, the result should be one entry in the + * mismatchKeySet because of the missing entry from the beginning of the test + */ + dbAudit.dbAudit(resourceName, A_SEQ_PU, nodeType); - @Before - public void setUp() { - logger.info("setUp: Entering"); + assertFalse(dbglog.getExtracted().isEmpty()); + + String mismatchIndex = dbglog.getExtracted().get(dbglog.getExtracted().size() - 1); + int mismatchEntries = mismatchIndex.trim().split(",").length; + logger.info("mismatchTest: mismatchIndex found: '" + mismatchIndex + "'" + " mismatachEntries = " + + mismatchEntries); - super.setUp(); + // Assert there is only one entry index + assertEquals(1, mismatchEntries); + + // Now check the entry in the error.log + assertFalse(errlog.getExtracted().isEmpty()); - dbDAO = null; - emf2 = null; - em2 = null; + String mismatchNum = errlog.getExtracted().get(errlog.getExtracted().size() - 1); - logger.info("setUp: Exiting"); - } + logger.info("mismatchTest: mismatchNum found: '" + mismatchNum + "'"); - @After - public void tearDown() { - logger.info("tearDown: Entering"); + // Assert that there are a total of 3 mismatches - 1 between each + // comparison node. + assertEquals("3", mismatchNum); + + logger.info("mismatchTest: Exit"); + } - if (dbDAO != null) { - dbDAO.destroy(); - } - - if (em2 != null) { - em2.close(); - } - - if (emf2 != null) { - emf2.close(); - } - - super.tearDown(); - - logger.info("tearDown: Exiting"); - } - - private void createDb(Properties properties) { - if (emf2 != null) { - throw new IllegalStateException("DB2 has already been created"); - } - - // open the DB and ensure it stays open until the test completes - emf2 = Persistence.createEntityManagerFactory(A_SEQ_PU, properties); - em2 = emf2.createEntityManager(); - - truncateTable(properties, A_SEQ_PU, "IntegrityAuditEntity"); - } - - /* - * Tests printing an error to the log in the event where there are no - * entities saved in the database - */ - @Test - public void noEntitiesTest() throws Exception { - Properties properties = makeProperties(); - - logger.info("noEntitiesTest: Entering"); - - dbDAO = new DbDAO(resourceName, A_SEQ_PU, properties); - dbDAO.deleteAllIntegrityAuditEntities(); - try { - DbAudit dbAudit = new DbAudit(dbDAO); - dbAudit.dbAudit(resourceName, A_SEQ_PU, nodeType); - fail("found unexpected entities"); - - } catch (DbAuditException e) { - - } - - logger.info("noEntitiesTest: Exit"); - } - - /* - * Tests the detection of only one entry in the database - */ - @Test - public void oneEntityTest() throws Exception { - Properties properties = makeProperties(); - - logger.info("oneEntityTest: Entering"); - - ExtractAppender log = watch(debugLogger, "DbAudit: Found only (one) IntegrityAuditEntity entry:"); - - // Add one entry in the database - dbDAO = new DbDAO(resourceName, A_SEQ_PU, properties); - DbAudit dbAudit = new DbAudit(dbDAO); - dbAudit.dbAudit(resourceName, A_SEQ_PU, nodeType); - - List<IntegrityAuditEntity> iaeList = dbDAO.getIntegrityAuditEntities(A_SEQ_PU, nodeType); - logger.info("List size: " + iaeList.size()); - - verifyItemsInLog(log, "one"); - - logger.info("oneEntityTest: Exit"); - } - - /* - * Tests reporting mismatches and missing entries using the error log - */ - @Test - public void mismatchTest() throws Exception { - logger.info("mismatchTest: Entering"); - - // use new URLs so we get a completely new DB - String dbUrl = DbAuditTest.dbUrl + "_mismatchTest"; - String dbUrl2 = dbUrl + "2"; - - Properties properties = makeProperties(); - properties.put(IntegrityAuditProperties.DB_URL, dbUrl); - - // Properties for DB2 - Properties properties2 = makeProperties(); - properties2.put(IntegrityAuditProperties.DB_URL, dbUrl2); - - /* - * We must drop and re-create DB1 so that it's sequence generator is in - * step with the sequence generator for DB2. - */ - recreateDb1(properties); - - // create/open DB2 - createDb(properties2); - - ExtractAppender dbglog = watch(debugLogger, "Mismatched entries [(]keys[)]:(.*)"); - ExtractAppender errlog = watch(errorLogger, "DB Audit: ([0-9])"); - - /* - * Create entries in DB1 & DB2 for the resource of interest - */ - dbDAO = new DbDAO(resourceName, A_SEQ_PU, properties); - - new DbDAO(resourceName, A_SEQ_PU, properties2).destroy(); - - /* - * Entries in DB1, pointing to DB2, except for pdp3 - */ - new DbDAO("pdp2", A_SEQ_PU, properties, dbUrl2).destroy(); - new DbDAO("pdp1", A_SEQ_PU, properties, dbUrl2).destroy(); - new DbDAO("pdp3", A_SEQ_PU, properties).destroy(); // mismatched URL - new DbDAO("pdp4", A_SEQ_PU, properties, dbUrl2).destroy(); - - /* - * Identical entries in DB2, all pointing to DB2, including pdp3, but - * leaving out pdp4 - */ - new DbDAO("pdp2", A_SEQ_PU, properties2).destroy(); - new DbDAO("pdp1", A_SEQ_PU, properties2).destroy(); - new DbDAO("pdp3", A_SEQ_PU, properties2).destroy(); - - /* - * Run the DB Audit, once it finds a mismatch and sleeps, update DB1 to - * have the same entry as DB2 it can be confirmed that the mismatch is - * resolved - */ - DbAudit dbAudit = new DbAudit(dbDAO); - dbAudit.dbAudit(resourceName, A_SEQ_PU, nodeType); - - // update pdp3 entry in DB1 to point to DB2 - new DbDAO("pdp3", A_SEQ_PU, properties, dbUrl2).destroy(); - - /* - * Run the audit again and correct the mismatch, the result should be - * one entry in the mismatchKeySet because of the missing entry from the - * beginning of the test - */ - dbAudit.dbAudit(resourceName, A_SEQ_PU, nodeType); - - assertFalse(dbglog.getExtracted().isEmpty()); - - String mismatchIndex = dbglog.getExtracted().get(dbglog.getExtracted().size() - 1); - int mismatchEntries = mismatchIndex.trim().split(",").length; - logger.info("mismatchTest: mismatchIndex found: '" + mismatchIndex + "'" + " mismatachEntries = " - + mismatchEntries); - - // Assert there is only one entry index - assertEquals(1, mismatchEntries); - - // Now check the entry in the error.log - assertFalse(errlog.getExtracted().isEmpty()); - - String mismatchNum = errlog.getExtracted().get(errlog.getExtracted().size() - 1); - - logger.info("mismatchTest: mismatchNum found: '" + mismatchNum + "'"); - - // Assert that there are a total of 3 mismatches - 1 between each - // comparison node. - assertEquals("3", mismatchNum); - - logger.info("mismatchTest: Exit"); - } - - /** - * Re-creates DB1, using the specified properties. - * @param properties - */ - private void recreateDb1(Properties properties) { - em.close(); - emf.close(); - - createDb(properties); - - em = em2; - emf = emf2; - - em2 = null; - emf2 = null; - } + /** + * Re-creates DB1, using the specified properties. + * + * @param properties the properties + */ + private void recreateDb1(Properties properties) { + em.close(); + emf.close(); + + createDb(properties); + + em = em2; + emf = emf2; + + em2 = null; + emf2 = null; + } } diff --git a/integrity-audit/src/test/java/org/onap/policy/common/ia/DbDAOTest.java b/integrity-audit/src/test/java/org/onap/policy/common/ia/DbDAOTest.java index c4cba280..01e2f2b0 100644 --- a/integrity-audit/src/test/java/org/onap/policy/common/ia/DbDAOTest.java +++ b/integrity-audit/src/test/java/org/onap/policy/common/ia/DbDAOTest.java @@ -30,6 +30,7 @@ import static org.junit.Assert.assertTrue; * where they have write privileges and can execute time-sensitive * tasks. */ + import java.util.Date; import java.util.HashSet; import java.util.List; @@ -58,393 +59,399 @@ import org.onap.policy.common.utils.jpa.EntityTransCloser; * tasks. */ public class DbDAOTest extends IntegrityAuditTestBase { - private static String resourceName = "pdp0"; - - private DbDAO d; - - @BeforeClass - public static void setUpBeforeClass() throws Exception { - IntegrityAuditTestBase.setUpBeforeClass(DEFAULT_DB_URL_PREFIX + DbDAOTest.class.getSimpleName()); - } - - @AfterClass - public static void tearDownAfterClass() { - IntegrityAuditTestBase.tearDownAfterClass(); - } - - @Before - public void setUp() { - super.setUp(); - d = null; - } - - @After - public void tearDown() { - if(d != null) { - d.destroy(); - } - - super.tearDown(); - } - - /* Tests registering a new IntegrityAuditEntity object in the DB */ - @Test - public void testNewRegistration() throws Exception { - Properties properties = makeProperties(); - - try(EntityTransCloser et = new EntityTransCloser(em.getTransaction())) { - d = new DbDAO(resourceName, A_SEQ_PU, properties); - - // Find the proper entry in the database - Query iaequery = em - .createQuery("Select i from IntegrityAuditEntity i where i.resourceName=:rn and i.persistenceUnit=:pu"); - iaequery.setParameter("rn", DbDAOTest.resourceName); - iaequery.setParameter("pu", DbDAOTest.A_SEQ_PU); - - @SuppressWarnings("rawtypes") - List iaeList = iaequery.getResultList(); - - // Assert that the IntegrityAuditEntity object was found - assertNotNull(iaeList); - - // flush to the DB - em.flush(); - et.commit(); - } - } - - /* - * Tests updating an IntegrityAuditEntity if it has already been registered - */ - @Test - public void testUpdateRegistration() throws Exception { - Properties properties = makeProperties(); - - d = new DbDAO(resourceName, A_SEQ_PU, properties); - - // Change site_name in properties to test that an update was made to - // an existing entry in the table - properties.put(IntegrityAuditProperties.SITE_NAME, "SiteB"); - d = new DbDAO(resourceName, A_SEQ_PU, properties); - - try(EntityTransCloser et = new EntityTransCloser(em.getTransaction())) { - // Find the proper entry in the database - Query iaequery = em - .createQuery("Select i from IntegrityAuditEntity i where i.resourceName=:rn and i.persistenceUnit=:pu"); - iaequery.setParameter("rn", DbDAOTest.resourceName); - iaequery.setParameter("pu", DbDAOTest.A_SEQ_PU); - - @SuppressWarnings("rawtypes") - List iaeList = iaequery.getResultList(); - IntegrityAuditEntity iae = null; - if (!iaeList.isEmpty()) { - // ignores multiple results - iae = (IntegrityAuditEntity) iaeList.get(0); - - em.refresh(iae); - em.persist(iae); - - // flush to the DB - em.flush(); - - // commit transaction - et.commit(); - - // Assert that the site_name for the existing entry was updated - assertEquals("SiteB", iae.getSite()); - } - } - } - - /* Tests obtaining all Integrity Audit Entities from a table */ - @Test - public void testGetIntegrityAuditEntities() throws Exception { - Properties properties = makeProperties(); - - // Add some entries to the DB - d = new DbDAO(resourceName, A_SEQ_PU, properties); - new DbDAO("pdp1", A_SEQ_PU, properties).destroy(); - properties.put(IntegrityAuditProperties.NODE_TYPE, "pdp_drools"); - new DbDAO("pdp2", A_SEQ_PU, properties).destroy(); - - List<IntegrityAuditEntity> entities; - // Obtain entries based on persistenceUnit and nodeType - entities = d.getIntegrityAuditEntities(A_SEQ_PU, "pdp_xacml"); - assertEquals(2, entities.size()); - } - - /* Tests retrieving a DbDAO instance's IntegrityAuditEntity */ - @Test - public void testGetMyIntegrityAuditEntity() throws Exception { - Properties properties = makeProperties(); - - d = new DbDAO(resourceName, A_SEQ_PU, properties); - IntegrityAuditEntity iae = d.getMyIntegrityAuditEntity(); - // assertEquals("integrityAuditPU", iae.getPersistenceUnit()); - assertEquals(A_SEQ_PU, iae.getPersistenceUnit()); - } - - /* Tests obtaining an IntegrityAuditEntity by ID */ - @Test - public void testGetIntegrityAuditEntity() throws Exception { - Properties properties = makeProperties(); - - // Obtain an entry from the database based on ID - d = new DbDAO(resourceName, A_SEQ_PU, properties); - - // Find the proper database entry - Query iaequery = em - .createQuery("Select i from IntegrityAuditEntity i where i.resourceName=:rn and i.persistenceUnit=:pu"); - iaequery.setParameter("rn", DbDAOTest.resourceName); - iaequery.setParameter("pu", DbDAOTest.A_SEQ_PU); - - @SuppressWarnings("rawtypes") - List iaeList = iaequery.getResultList(); - IntegrityAuditEntity iae = null; - if (!iaeList.isEmpty()) { - // ignores multiple results - iae = (IntegrityAuditEntity) iaeList.get(0); - - // refresh the object from DB in case cached data was returned - em.refresh(iae); - - // Obtain ID for an IntegrityAuditEntity - PersistenceUnitUtil util = emf.getPersistenceUnitUtil(); - Object iaeId = util.getIdentifier(iae); - - // Obtain the same IntegrityAuditEntity based on ID - IntegrityAuditEntity iaeDuplicate = d.getIntegrityAuditEntity((long) iaeId); - Object duplicateId = util.getIdentifier(iaeDuplicate); - - // Assert that the proper entry was retrieved based on ID - assertEquals((long) iaeId, (long) duplicateId); - } - } - - /* Tests setting an IntegrityAuditEntity as the designated node */ - @Test - public void testSetDesignated() throws Exception { - Properties properties = makeProperties(); - - try(EntityTransCloser et = new EntityTransCloser(em.getTransaction())) { - // Create an entry and set it's designated field to true - d = new DbDAO(resourceName, A_SEQ_PU, properties); - d.setDesignated(resourceName, A_SEQ_PU, true); - - // Find the proper entry in the database - Query iaequery = em - .createQuery("Select i from IntegrityAuditEntity i where i.resourceName=:rn and i.persistenceUnit=:pu"); - iaequery.setParameter("rn", resourceName); - iaequery.setParameter("pu", A_SEQ_PU); - - @SuppressWarnings("rawtypes") - List iaeList = iaequery.getResultList(); - IntegrityAuditEntity iae = null; - - if (!iaeList.isEmpty()) { - // ignores multiple results - iae = (IntegrityAuditEntity) iaeList.get(0); - em.refresh(iae); - - // Check if the node is designated - boolean result = iae.isDesignated(); - - // Assert that it is designated - assertTrue(result); - } - - // flush to the DB - em.flush(); - - // close the transaction - et.commit(); - } - } - - /* Tests that the lastUpdated column in the database is updated properly */ - @Test - public void testSetLastUpdated() throws Exception { - Properties properties = makeProperties(); - - try(EntityTransCloser et = new EntityTransCloser(em.getTransaction())) { - // Create an entry - d = new DbDAO(resourceName, A_SEQ_PU, properties); - - // Find the proper entry in the database - Query iaequery = em - .createQuery("Select i from IntegrityAuditEntity i where i.resourceName=:rn and i.persistenceUnit=:pu"); - iaequery.setParameter("rn", resourceName); - iaequery.setParameter("pu", A_SEQ_PU); - - @SuppressWarnings("rawtypes") - List iaeList = iaequery.getResultList(); - IntegrityAuditEntity iae = null; - - if (!iaeList.isEmpty()) { - // ignores multiple results - iae = (IntegrityAuditEntity) iaeList.get(0); - // refresh the object from DB in case cached data was returned - em.refresh(iae); - - // Obtain old update value and set new update value - Date oldDate = iae.getLastUpdated(); - - // ensure dates are different by sleeping for a bit - Thread.sleep(1); - - iae.setSite("SiteB"); - iae.setLastUpdated(new Date()); - Date newDate = iae.getLastUpdated(); - - em.persist(iae); - // flush to the DB - em.flush(); - // close the transaction - et.commit(); - - // Assert that the old and new update times are different - assertNotEquals(oldDate, newDate); - } - } - } - - /* Tests that all the entries from a class can be retrieved */ - @Test - public void testGetAllMyEntriesString() throws Exception { - Properties properties = makeProperties(); - - // create entries for the IntegrityAuditEntity table - d = new DbDAO(resourceName, A_SEQ_PU, properties); - new DbDAO("pdp1", A_SEQ_PU, properties).destroy(); - new DbDAO("pdp2", A_SEQ_PU, properties).destroy(); - - // Obtain a hash with the persisted objects - Map<Object, Object> entries = d.getAllMyEntries("org.onap.policy.common.ia.jpa.IntegrityAuditEntity"); - - // Assert there were 3 entries for that class - assertEquals(3, entries.size()); - } - - /* - * Tests retrieving all entities in a Persistence Unit using the class name - * and a hashset of IDs - */ - @Test - public void testGetAllMyEntriesStringHashSet() throws Exception { - Properties properties = makeProperties(); - - // create entries for the IntegrityAuditEntity table - d = new DbDAO(resourceName, A_SEQ_PU, properties); - new DbDAO("pdp1", A_SEQ_PU, properties).destroy(); - new DbDAO("pdp2", A_SEQ_PU, properties).destroy(); - - // Obtain all entity keys - CriteriaBuilder cb = em.getCriteriaBuilder(); - CriteriaQuery<Object> cq = cb.createQuery(); - Root<?> rootEntry = cq.from(Class.forName("org.onap.policy.common.ia.jpa.IntegrityAuditEntity")); - CriteriaQuery<Object> all = cq.select(rootEntry); - TypedQuery<Object> allQuery = em.createQuery(all); - List<Object> objectList = allQuery.getResultList(); - HashSet<Object> resultSet = new HashSet<Object>(); - PersistenceUnitUtil util = emf.getPersistenceUnitUtil(); - for (Object o : objectList) { - Object key = util.getIdentifier(o); - resultSet.add(key); - } - - // Obtain a hash with the persisted objects - Map<Object, Object> entries = d.getAllMyEntries("org.onap.policy.common.ia.jpa.IntegrityAuditEntity", - resultSet); - - // Assert there were 3 entries for that class - assertEquals(3, entries.size()); - } - - /* - * Tests retrieving all entities in a Persistence Unit using the persistence - * unit, properties, and class name - */ - @Test - public void testGetAllEntriesStringPropertiesString() throws Exception { - Properties properties = makeProperties(); - - // create entries for the IntegrityAuditEntity table - d = new DbDAO(resourceName, A_SEQ_PU, properties); - new DbDAO("pdp1", A_SEQ_PU, properties).destroy(); - new DbDAO("pdp2", A_SEQ_PU, properties).destroy(); - - // Obtain a hash with the persisted objects - Map<Object, Object> entries = d.getAllEntries("integrityAuditPU", properties, - "org.onap.policy.common.ia.jpa.IntegrityAuditEntity"); - - // Assert there were 3 entries for that class - assertEquals(3, entries.size()); - } - - /* - * Tests retrieving all entities in a Persistence Unit using the persistence - * unit, properties, class name, and a hashset of IDs - */ - @Test - public void testGetAllEntriesStringPropertiesStringHashSet() throws Exception { - Properties properties = makeProperties(); - - // create entries for the IntegrityAuditEntity table - d = new DbDAO(resourceName, A_SEQ_PU, properties); - new DbDAO("pdp1", A_SEQ_PU, properties).destroy(); - new DbDAO("pdp2", A_SEQ_PU, properties).destroy(); - - // Obtain all entity keys - CriteriaBuilder cb = em.getCriteriaBuilder(); - CriteriaQuery<Object> cq = cb.createQuery(); - Root<?> rootEntry = cq.from(Class.forName("org.onap.policy.common.ia.jpa.IntegrityAuditEntity")); - CriteriaQuery<Object> all = cq.select(rootEntry); - TypedQuery<Object> allQuery = em.createQuery(all); - List<Object> objectList = allQuery.getResultList(); - HashSet<Object> resultSet = new HashSet<Object>(); - PersistenceUnitUtil util = emf.getPersistenceUnitUtil(); - for (Object o : objectList) { - Object key = util.getIdentifier(o); - resultSet.add(key); - } - - // Obtain a hash with the persisted objects - Map<Object, Object> entries = d.getAllEntries("integrityAuditPU", properties, - "org.onap.policy.common.ia.jpa.IntegrityAuditEntity", resultSet); - - // Assert there were 3 entries for that class - assertEquals(3, entries.size()); - } - - /* - * Tests getting all the entries from a class based on persistenceUnit, - * properties, and className - */ - @Test - public void testGetAllEntries() throws Exception { - Properties properties = makeProperties(); - - // create entries for the IntegrityAuditEntity table - d = new DbDAO(resourceName, A_SEQ_PU, properties); - new DbDAO("pdp1", A_SEQ_PU, properties).destroy(); - new DbDAO("pdp2", A_SEQ_PU, properties).destroy(); - - // Obtain a hash with the persisted objects - Map<Object, Object> entries = d.getAllEntries(A_SEQ_PU, properties, - "org.onap.policy.common.ia.jpa.IntegrityAuditEntity"); - - // Assert there were 3 entries for that class - assertEquals(3, entries.size()); - } - - /* Tests obtaining all class names of persisted classes */ - public void testGetPersistenceClassNames() throws Exception { - Properties properties = makeProperties(); - - d = new DbDAO(resourceName, A_SEQ_PU, properties); - - // Retrieve persistence class names - Set<String> result = d.getPersistenceClassNames(); - assertEquals(1, result.size()); - } + private static String resourceName = "pdp0"; + + private DbDAO dbDao; + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + IntegrityAuditTestBase.setUpBeforeClass(DEFAULT_DB_URL_PREFIX + DbDAOTest.class.getSimpleName()); + } + + @AfterClass + public static void tearDownAfterClass() { + IntegrityAuditTestBase.tearDownAfterClass(); + } + + @Override + @Before + public void setUp() { + super.setUp(); + dbDao = null; + } + + /** + * Tear down after test cases. + */ + @Override + @After + public void tearDown() { + if (dbDao != null) { + dbDao.destroy(); + } + + super.tearDown(); + } + + /* Tests registering a new IntegrityAuditEntity object in the DB */ + @Test + public void testNewRegistration() throws Exception { + Properties properties = makeProperties(); + + try (EntityTransCloser et = new EntityTransCloser(em.getTransaction())) { + dbDao = new DbDAO(resourceName, A_SEQ_PU, properties); + + // Find the proper entry in the database + Query iaequery = em.createQuery( + "Select i from IntegrityAuditEntity i where i.resourceName=:rn and i.persistenceUnit=:pu"); + iaequery.setParameter("rn", DbDAOTest.resourceName); + iaequery.setParameter("pu", DbDAOTest.A_SEQ_PU); + + @SuppressWarnings("rawtypes") + List iaeList = iaequery.getResultList(); + + // Assert that the IntegrityAuditEntity object was found + assertNotNull(iaeList); + + // flush to the DB + em.flush(); + et.commit(); + } + } + + /* + * Tests updating an IntegrityAuditEntity if it has already been registered + */ + @Test + public void testUpdateRegistration() throws Exception { + Properties properties = makeProperties(); + + dbDao = new DbDAO(resourceName, A_SEQ_PU, properties); + + // Change site_name in properties to test that an update was made to + // an existing entry in the table + properties.put(IntegrityAuditProperties.SITE_NAME, "SiteB"); + dbDao = new DbDAO(resourceName, A_SEQ_PU, properties); + + try (EntityTransCloser et = new EntityTransCloser(em.getTransaction())) { + // Find the proper entry in the database + Query iaequery = em.createQuery( + "Select i from IntegrityAuditEntity i where i.resourceName=:rn and i.persistenceUnit=:pu"); + iaequery.setParameter("rn", DbDAOTest.resourceName); + iaequery.setParameter("pu", DbDAOTest.A_SEQ_PU); + + @SuppressWarnings("rawtypes") + List iaeList = iaequery.getResultList(); + IntegrityAuditEntity iae = null; + if (!iaeList.isEmpty()) { + // ignores multiple results + iae = (IntegrityAuditEntity) iaeList.get(0); + + em.refresh(iae); + em.persist(iae); + + // flush to the DB + em.flush(); + + // commit transaction + et.commit(); + + // Assert that the site_name for the existing entry was updated + assertEquals("SiteB", iae.getSite()); + } + } + } + + /* Tests obtaining all Integrity Audit Entities from a table */ + @Test + public void testGetIntegrityAuditEntities() throws Exception { + Properties properties = makeProperties(); + + // Add some entries to the DB + dbDao = new DbDAO(resourceName, A_SEQ_PU, properties); + new DbDAO("pdp1", A_SEQ_PU, properties).destroy(); + properties.put(IntegrityAuditProperties.NODE_TYPE, "pdp_drools"); + new DbDAO("pdp2", A_SEQ_PU, properties).destroy(); + + List<IntegrityAuditEntity> entities; + // Obtain entries based on persistenceUnit and nodeType + entities = dbDao.getIntegrityAuditEntities(A_SEQ_PU, "pdp_xacml"); + assertEquals(2, entities.size()); + } + + /* Tests retrieving a DbDAO instance's IntegrityAuditEntity */ + @Test + public void testGetMyIntegrityAuditEntity() throws Exception { + Properties properties = makeProperties(); + + dbDao = new DbDAO(resourceName, A_SEQ_PU, properties); + IntegrityAuditEntity iae = dbDao.getMyIntegrityAuditEntity(); + // assertEquals("integrityAuditPU", iae.getPersistenceUnit()); + assertEquals(A_SEQ_PU, iae.getPersistenceUnit()); + } + + /* Tests obtaining an IntegrityAuditEntity by ID */ + @Test + public void testGetIntegrityAuditEntity() throws Exception { + Properties properties = makeProperties(); + + // Obtain an entry from the database based on ID + dbDao = new DbDAO(resourceName, A_SEQ_PU, properties); + + // Find the proper database entry + Query iaequery = em + .createQuery("Select i from IntegrityAuditEntity i where i.resourceName=:rn and i.persistenceUnit=:pu"); + iaequery.setParameter("rn", DbDAOTest.resourceName); + iaequery.setParameter("pu", DbDAOTest.A_SEQ_PU); + + @SuppressWarnings("rawtypes") + List iaeList = iaequery.getResultList(); + IntegrityAuditEntity iae = null; + if (!iaeList.isEmpty()) { + // ignores multiple results + iae = (IntegrityAuditEntity) iaeList.get(0); + + // refresh the object from DB in case cached data was returned + em.refresh(iae); + + // Obtain ID for an IntegrityAuditEntity + PersistenceUnitUtil util = emf.getPersistenceUnitUtil(); + Object iaeId = util.getIdentifier(iae); + + // Obtain the same IntegrityAuditEntity based on ID + IntegrityAuditEntity iaeDuplicate = dbDao.getIntegrityAuditEntity((long) iaeId); + Object duplicateId = util.getIdentifier(iaeDuplicate); + + // Assert that the proper entry was retrieved based on ID + assertEquals((long) iaeId, (long) duplicateId); + } + } + + /* Tests setting an IntegrityAuditEntity as the designated node */ + @Test + public void testSetDesignated() throws Exception { + Properties properties = makeProperties(); + + try (EntityTransCloser et = new EntityTransCloser(em.getTransaction())) { + // Create an entry and set it's designated field to true + dbDao = new DbDAO(resourceName, A_SEQ_PU, properties); + dbDao.setDesignated(resourceName, A_SEQ_PU, true); + + // Find the proper entry in the database + Query iaequery = em.createQuery( + "Select i from IntegrityAuditEntity i where i.resourceName=:rn and i.persistenceUnit=:pu"); + iaequery.setParameter("rn", resourceName); + iaequery.setParameter("pu", A_SEQ_PU); + + @SuppressWarnings("rawtypes") + List iaeList = iaequery.getResultList(); + IntegrityAuditEntity iae = null; + + if (!iaeList.isEmpty()) { + // ignores multiple results + iae = (IntegrityAuditEntity) iaeList.get(0); + em.refresh(iae); + + // Check if the node is designated + boolean result = iae.isDesignated(); + + // Assert that it is designated + assertTrue(result); + } + + // flush to the DB + em.flush(); + + // close the transaction + et.commit(); + } + } + + /* Tests that the lastUpdated column in the database is updated properly */ + @Test + public void testSetLastUpdated() throws Exception { + Properties properties = makeProperties(); + + try (EntityTransCloser et = new EntityTransCloser(em.getTransaction())) { + // Create an entry + dbDao = new DbDAO(resourceName, A_SEQ_PU, properties); + + // Find the proper entry in the database + Query iaequery = em.createQuery( + "Select i from IntegrityAuditEntity i where i.resourceName=:rn and i.persistenceUnit=:pu"); + iaequery.setParameter("rn", resourceName); + iaequery.setParameter("pu", A_SEQ_PU); + + @SuppressWarnings("rawtypes") + List iaeList = iaequery.getResultList(); + IntegrityAuditEntity iae = null; + + if (!iaeList.isEmpty()) { + // ignores multiple results + iae = (IntegrityAuditEntity) iaeList.get(0); + // refresh the object from DB in case cached data was returned + em.refresh(iae); + + // Obtain old update value and set new update value + final Date oldDate = iae.getLastUpdated(); + + // ensure dates are different by sleeping for a bit + Thread.sleep(1); + + iae.setSite("SiteB"); + iae.setLastUpdated(new Date()); + final Date newDate = iae.getLastUpdated(); + + em.persist(iae); + // flush to the DB + em.flush(); + // close the transaction + et.commit(); + + // Assert that the old and new update times are different + assertNotEquals(oldDate, newDate); + } + } + } + + /* Tests that all the entries from a class can be retrieved */ + @Test + public void testGetAllMyEntriesString() throws Exception { + Properties properties = makeProperties(); + + // create entries for the IntegrityAuditEntity table + dbDao = new DbDAO(resourceName, A_SEQ_PU, properties); + new DbDAO("pdp1", A_SEQ_PU, properties).destroy(); + new DbDAO("pdp2", A_SEQ_PU, properties).destroy(); + + // Obtain a hash with the persisted objects + Map<Object, Object> entries = dbDao.getAllMyEntries("org.onap.policy.common.ia.jpa.IntegrityAuditEntity"); + + // Assert there were 3 entries for that class + assertEquals(3, entries.size()); + } + + /* + * Tests retrieving all entities in a Persistence Unit using the class name and a hashset of IDs + */ + @Test + public void testGetAllMyEntriesStringHashSet() throws Exception { + Properties properties = makeProperties(); + + // create entries for the IntegrityAuditEntity table + dbDao = new DbDAO(resourceName, A_SEQ_PU, properties); + new DbDAO("pdp1", A_SEQ_PU, properties).destroy(); + new DbDAO("pdp2", A_SEQ_PU, properties).destroy(); + + // Obtain all entity keys + CriteriaBuilder cb = em.getCriteriaBuilder(); + CriteriaQuery<Object> cq = cb.createQuery(); + Root<?> rootEntry = cq.from(Class.forName("org.onap.policy.common.ia.jpa.IntegrityAuditEntity")); + CriteriaQuery<Object> all = cq.select(rootEntry); + TypedQuery<Object> allQuery = em.createQuery(all); + List<Object> objectList = allQuery.getResultList(); + HashSet<Object> resultSet = new HashSet<Object>(); + PersistenceUnitUtil util = emf.getPersistenceUnitUtil(); + for (Object o : objectList) { + Object key = util.getIdentifier(o); + resultSet.add(key); + } + + // Obtain a hash with the persisted objects + Map<Object, Object> entries = + dbDao.getAllMyEntries("org.onap.policy.common.ia.jpa.IntegrityAuditEntity", resultSet); + + // Assert there were 3 entries for that class + assertEquals(3, entries.size()); + } + + /* + * Tests retrieving all entities in a Persistence Unit using the persistence unit, properties, + * and class name + */ + @Test + public void testGetAllEntriesStringPropertiesString() throws Exception { + Properties properties = makeProperties(); + + // create entries for the IntegrityAuditEntity table + dbDao = new DbDAO(resourceName, A_SEQ_PU, properties); + new DbDAO("pdp1", A_SEQ_PU, properties).destroy(); + new DbDAO("pdp2", A_SEQ_PU, properties).destroy(); + + // Obtain a hash with the persisted objects + Map<Object, Object> entries = dbDao.getAllEntries("integrityAuditPU", properties, + "org.onap.policy.common.ia.jpa.IntegrityAuditEntity"); + + // Assert there were 3 entries for that class + assertEquals(3, entries.size()); + } + + /* + * Tests retrieving all entities in a Persistence Unit using the persistence unit, properties, + * class name, and a hashset of IDs + */ + @Test + public void testGetAllEntriesStringPropertiesStringHashSet() throws Exception { + Properties properties = makeProperties(); + + // create entries for the IntegrityAuditEntity table + dbDao = new DbDAO(resourceName, A_SEQ_PU, properties); + new DbDAO("pdp1", A_SEQ_PU, properties).destroy(); + new DbDAO("pdp2", A_SEQ_PU, properties).destroy(); + + // Obtain all entity keys + CriteriaBuilder cb = em.getCriteriaBuilder(); + CriteriaQuery<Object> cq = cb.createQuery(); + Root<?> rootEntry = cq.from(Class.forName("org.onap.policy.common.ia.jpa.IntegrityAuditEntity")); + CriteriaQuery<Object> all = cq.select(rootEntry); + TypedQuery<Object> allQuery = em.createQuery(all); + List<Object> objectList = allQuery.getResultList(); + HashSet<Object> resultSet = new HashSet<Object>(); + PersistenceUnitUtil util = emf.getPersistenceUnitUtil(); + for (Object o : objectList) { + Object key = util.getIdentifier(o); + resultSet.add(key); + } + + // Obtain a hash with the persisted objects + Map<Object, Object> entries = dbDao.getAllEntries("integrityAuditPU", properties, + "org.onap.policy.common.ia.jpa.IntegrityAuditEntity", resultSet); + + // Assert there were 3 entries for that class + assertEquals(3, entries.size()); + } + + /* + * Tests getting all the entries from a class based on persistenceUnit, properties, and + * className + */ + @Test + public void testGetAllEntries() throws Exception { + Properties properties = makeProperties(); + + // create entries for the IntegrityAuditEntity table + dbDao = new DbDAO(resourceName, A_SEQ_PU, properties); + new DbDAO("pdp1", A_SEQ_PU, properties).destroy(); + new DbDAO("pdp2", A_SEQ_PU, properties).destroy(); + + // Obtain a hash with the persisted objects + Map<Object, Object> entries = + dbDao.getAllEntries(A_SEQ_PU, properties, "org.onap.policy.common.ia.jpa.IntegrityAuditEntity"); + + // Assert there were 3 entries for that class + assertEquals(3, entries.size()); + } + + /** + * Tests obtaining all class names of persisted classes. + */ + public void testGetPersistenceClassNames() throws Exception { + Properties properties = makeProperties(); + + dbDao = new DbDAO(resourceName, A_SEQ_PU, properties); + + // Retrieve persistence class names + Set<String> result = dbDao.getPersistenceClassNames(); + assertEquals(1, result.size()); + } } diff --git a/integrity-audit/src/test/java/org/onap/policy/common/ia/ExceptionsTest.java b/integrity-audit/src/test/java/org/onap/policy/common/ia/ExceptionsTest.java index b02b0c7f..3c8ce528 100644 --- a/integrity-audit/src/test/java/org/onap/policy/common/ia/ExceptionsTest.java +++ b/integrity-audit/src/test/java/org/onap/policy/common/ia/ExceptionsTest.java @@ -23,10 +23,6 @@ package org.onap.policy.common.ia; import static org.junit.Assert.assertEquals; import org.junit.Test; -import org.onap.policy.common.ia.DbAuditException; -import org.onap.policy.common.ia.DbDaoTransactionException; -import org.onap.policy.common.ia.IntegrityAuditException; -import org.onap.policy.common.ia.IntegrityAuditPropertiesException; import org.onap.policy.common.utils.test.ExceptionsTester; /** @@ -34,23 +30,23 @@ import org.onap.policy.common.utils.test.ExceptionsTester; */ public class ExceptionsTest extends ExceptionsTester { - @Test - public void testDbAuditException() throws Exception { - assertEquals(4, test(DbAuditException.class)); - } - - @Test - public void testDbDaoTransactionException() throws Exception { - assertEquals(4, test(DbDaoTransactionException.class)); - } - - @Test - public void testIntegrityAuditException() throws Exception { - assertEquals(4, test(IntegrityAuditException.class)); - } - - @Test - public void testIntegrityAuditPropertiesException() throws Exception { - assertEquals(4, test(IntegrityAuditPropertiesException.class)); - } + @Test + public void testDbAuditException() throws Exception { + assertEquals(4, test(DbAuditException.class)); + } + + @Test + public void testDbDaoTransactionException() throws Exception { + assertEquals(4, test(DbDaoTransactionException.class)); + } + + @Test + public void testIntegrityAuditException() throws Exception { + assertEquals(4, test(IntegrityAuditException.class)); + } + + @Test + public void testIntegrityAuditPropertiesException() throws Exception { + assertEquals(4, test(IntegrityAuditPropertiesException.class)); + } } diff --git a/integrity-audit/src/test/java/org/onap/policy/common/ia/IntegrityAuditDesignationTest.java b/integrity-audit/src/test/java/org/onap/policy/common/ia/IntegrityAuditDesignationTest.java index 1861787a..69f37da5 100644 --- a/integrity-audit/src/test/java/org/onap/policy/common/ia/IntegrityAuditDesignationTest.java +++ b/integrity-audit/src/test/java/org/onap/policy/common/ia/IntegrityAuditDesignationTest.java @@ -30,590 +30,573 @@ import org.onap.policy.common.logging.flexlogger.Logger; import org.onap.policy.common.utils.test.log.logback.ExtractAppender; /** - * All JUnits are designed to run in the local development environment where - * they have write privileges and can execute time-sensitive tasks. - * <p/> - * Many of the test verification steps are performed by scanning for items - * written to the log file. Rather than actually scan the log file, an - * {@link ExtractAppender} is used to monitor events that are logged and extract - * relevant items. In order to attach the appender to the debug log, it assumes - * that the debug log is a <i>logback</i> Logger configured per EELF. - * <p/> - * These tests use a temporary, in-memory DB, which is dropped once the tests - * complete. + * All JUnits are designed to run in the local development environment where they have write + * privileges and can execute time-sensitive tasks. + * + * <p>Many of the test verification steps are performed by scanning for items written to the log + * file. Rather than actually scan the log file, an {@link ExtractAppender} is used to monitor + * events that are logged and extract relevant items. In order to attach the appender to the debug + * log, it assumes that the debug log is a <i>logback</i> Logger configured per EELF. + * + * <p>These tests use a temporary, in-memory DB, which is dropped once the tests complete. */ public class IntegrityAuditDesignationTest extends IntegrityAuditTestBase { - private static Logger logger = FlexLogger.getLogger(IntegrityAuditDesignationTest.class); - - /** - * Matches specified PDPs in the debug log. A regular expression matching - * the desired PDPs should be appended, followed by a right parenthesis. For - * example: - * - * <pre> - * <code>new ExtractAppender(START_AUDIT_RE_PREFIX + "pdp[124])") - * </code> - * </pre> - */ - private static final String START_AUDIT_RE_PREFIX = "Starting audit simulation for resourceName=("; - - @BeforeClass - public static void setUpBeforeClass() throws Exception { - IntegrityAuditTestBase - .setUpBeforeClass(DEFAULT_DB_URL_PREFIX + IntegrityAuditDesignationTest.class.getSimpleName()); - } - - @AfterClass - public static void tearDownAfterClass() { - IntegrityAuditTestBase.tearDownAfterClass(); - } - - @Before - public void setUp() { - logger.info("setUp: Entering"); - - super.setUp(); - - logger.info("setUp: Exiting"); - } - - @After - public void tearDown() { - logger.info("tearDown: Entering"); - - super.tearDown(); - - logger.info("tearDown: Exiting"); - - } - - /* - * Tests designation logic when only one functioning resource is in play. - * Designation should stay with single resource. - * - * Note: console.log must be examined to ascertain whether or not this test - * was successful. - */ - @Test - public void testOneResource() throws Exception { - - logger.info("testOneResource: Entering"); - - ExtractAppender logA = watch(debugLogger, START_AUDIT_RE); - - MyIntegrityAudit integrityAudit = makeAuditor("pdp1", A_SEQ_PU); - - /* - * Wait for - * - * 1) pdp1 to run audit - * - * 2) Logic to detect that no other node is available for designation - * - * 3) pdp1 to run audit again - */ - runAudit(integrityAudit); - waitStaleAndRun(integrityAudit); - - logger.info("testOneResource: Stopping audit thread"); - integrityAudit.stopAuditThread(); - - verifyItemsInLog(logA, "pdp1"); - - /* - * Test fix for ONAPD2TD-783: Audit fails to run when application is - * restarted. - */ - integrityAudit.startAuditThread(); - - /* - * Sleep long enough to allow - * - * 1) pdp1 to run audit - * - * 2) Logic to detect that no other node is available for designation - * - * 3) pdp1 to run audit again - */ - runAudit(integrityAudit); - waitStaleAndRun(integrityAudit); - - verifyItemsInLog(logA, "pdp1"); - - logger.info("testOneResource: Exiting"); - - } - - /* - * Tests designation logic when two functioning resources are in play. - * Designation should alternate between resources. - * - * Note: console.log must be examined to ascertain whether or not this test - * was successful. A quick way of examining the log is to search for the - * string "audit simulation": - * - * As you can see from the "dbAuditSimulate" method, when it executes, it - * logs the "Starting audit simulation..." message and when it finishes, it - * logs the "Finished audit simulation..." message. By looking for these - * messages, you can verify that the audits are run by the proper resource. - * For example, when testFourResourcesOneDead is run, you should see a - * Starting.../Finished... sequence for "pdp1", followed by a - * Starting.../Finished... sequence for pdp2, followed by a - * Starting.../Finished... sequence for pdp4 (pdp3 is skipped as it's - * dead/hung), followed by a Starting.../Finished... sequence for "pdp1", - * etc. - */ - @Test - public void testTwoResources() throws Exception { - - logger.info("testTwoResources: Entering"); - - ExtractAppender logA = watch(debugLogger, START_AUDIT_RE); - - /* - * Start audit for pdp1. - */ - MyIntegrityAudit integrityAudit = makeAuditor("pdp1", A_SEQ_PU); - - /* - * Start audit for pdp2. - */ - MyIntegrityAudit integrityAudit2 = makeAuditor("pdp2", A_SEQ_PU); - - /* - * Sleep long enough to allow - * - * 1) pdp1 to run audit - * - * 2) Logic to detect that pdp1 is stale and designate pdp2 - * - * 3) pdp2 to run audit - * - * 4) Logic to detect that pdp2 is stale and designate pdp1 - * - * 5) pdp1 to run audit - */ - runAudit(integrityAudit); - waitStaleAndRun(integrityAudit2); - waitStaleAndRun(integrityAudit); - - verifyItemsInLog(logA, "pdp1", "pdp2", "pdp1"); - - logger.info("testTwoResources: Exiting"); - - } - - /* - * Tests designation logic when two functioning resources are in play, each - * with different PUs. Audits for persistenceUnit and PU_B should run - * simultaneously. Designation should not alternate. - * - * Note: console.log must be examined to ascertain whether or not this test - * was successful. - */ - @Test - public void testTwoResourcesDifferentPus() throws Exception { - - logger.info("testTwoResourcesDifferentPus: Entering"); - - ExtractAppender logA = watch(debugLogger, START_AUDIT_RE_PREFIX + "pdp1)"); - ExtractAppender logB = watch(debugLogger, START_AUDIT_RE_PREFIX + "pdp2)"); - - /* - * Start audit for pdp1. - */ - MyIntegrityAudit integrityAudit = makeAuditor("pdp1", A_SEQ_PU); - - /* - * Start audit for pdp2. - */ - MyIntegrityAudit integrityAudit2 = makeAuditor("pdp2", B_SEQ_PU); - - /* - * Sleep long enough to allow - * - * 1) pdp1 and pdp2 to run audit simultaneously - * - * 2) Logic to detect that no other node is available for designation - * for either pdp1 or pdp2 - * - * 3) pdp1 and pdp2 to again run audit simultaneously - */ - runAudit(integrityAudit, integrityAudit2); - waitStaleAndRun(integrityAudit, integrityAudit2); - - verifyItemsInLog(logA, "pdp1", "pdp1"); - verifyItemsInLog(logB, "pdp2", "pdp2"); - - logger.info("testTwoResourcesDifferentPus: Exiting"); - - } - - /* - * Tests designation logic when two resources are in play but one of them is - * dead/hung. Designation should move to second resource but then get - * restored back to original resource when it's discovered that second - * resource is dead. - * - * Note: console.log must be examined to ascertain whether or not this test - * was successful. - */ - @Test - public void testTwoResourcesOneDead() throws Exception { - - logger.info("testTwoResourcesOneDead: Entering"); - - ExtractAppender logA = watch(debugLogger, START_AUDIT_RE); - - /* - * Start audit for pdp1. - */ - MyIntegrityAudit integrityAudit = makeAuditor("pdp1", A_SEQ_PU); - - /* - * Populate DB for pdp2, which will simulate it having registered but - * then having died. - */ - new DbDAO("pdp2", A_SEQ_PU, makeProperties()).destroy(); - - /* - * Sleep long enough to allow - * - * 1) pdp1 to run audit - * - * 2) Logic to detect that other node, pdp2, is not available for - * designation - * - * 3) pdp1 to run audit again - */ - runAudit(integrityAudit); - waitStaleAndRun(integrityAudit); - - verifyItemsInLog(logA, "pdp1", "pdp1"); - - logger.info("testTwoResourcesOneDead: Exiting"); - - } - - /* - * Tests designation logic when three functioning resources are in play. - * Designation should round robin among resources. - * - * Note: console.log must be examined to ascertain whether or not this test - * was successful. - */ - @Test - public void testThreeResources() throws Exception { - - logger.info("testThreeResources: Entering"); - - ExtractAppender logA = watch(debugLogger, START_AUDIT_RE); - - /* - * Start audit for pdp1. - */ - MyIntegrityAudit integrityAudit = makeAuditor("pdp1", A_SEQ_PU); - - /* - * Start audit for pdp2. - */ - MyIntegrityAudit integrityAudit2 = makeAuditor("pdp2", A_SEQ_PU); - - /* - * Start audit for pdp3. - */ - MyIntegrityAudit integrityAudit3 = makeAuditor("pdp3", A_SEQ_PU); - - /* - * Sleep long enough to allow - * - * 1) pdp1 to run audit - * - * 2) Logic to detect that pdp1 is stale and designate pdp2 - * - * 3) pdp2 to run audit - * - * 4) Logic to detect that pdp2 is stale and designate pdp3 - * - * 5) pdp3 to run audit - * - * 6) Logic to detect that pdp3 is stale and designate pdp1 - * - * 7) pdp1 to run audit - */ - runAudit(integrityAudit); - waitStaleAndRun(integrityAudit2); - waitStaleAndRun(integrityAudit3); - waitStaleAndRun(integrityAudit); - - verifyItemsInLog(logA, "pdp1", "pdp2", "pdp3", "pdp1"); - - logger.info("testThreeResources: Exiting"); - - } - - /* - * Tests designation logic when four functioning resources are in play, two - * with one PU, two with another. Audits for persistenceUnit and PU_B should - * run simultaneously. Designation should alternate between resources for - * each of the two persistence units. - * - * Note: console.log must be examined to ascertain whether or not this test - * was successful. - */ - @Test - public void testFourResourcesDifferentPus() throws Exception { - - logger.info("testFourResourcesDifferentPus: Entering"); - - ExtractAppender logA = watch(debugLogger, START_AUDIT_RE_PREFIX + "pdp1|pdp3)"); - ExtractAppender logB = watch(debugLogger, START_AUDIT_RE_PREFIX + "pdp2|pdp4)"); - - /* - * Start audit for "pdp1", testPU. - */ - MyIntegrityAudit integrityAudit = makeAuditor("pdp1", A_SEQ_PU); - - /* - * Start audit for pdp2, integrityAuditPU. - */ - MyIntegrityAudit integrityAudit2 = makeAuditor("pdp2", B_SEQ_PU); - - /* - * Start audit for pdp3, testPU. - */ - MyIntegrityAudit integrityAudit3 = makeAuditor("pdp3", A_SEQ_PU); - - /* - * Start audit for pdp4, integrityAuditPU. - */ - MyIntegrityAudit integrityAudit4 = makeAuditor("pdp4", B_SEQ_PU); - - /* - * Sleep long enough to allow - * - * 1) pdp1 and pdp2 to run audit simultaneously - * - * 2) Logic to detect that pdp1 and pdp2 are stale and designate pdp3 - * (one's counterpart) and pdp4 (two's counterpart) - * - * 3) pdp3 and pdp4 to run audit simultaneously - * - * 4) Logic to detect that pdp3 and pdp4 are stale and designate pdp1 - * (three's counterpart) and pdp2 (four's counterpart) - * - * 5) pdp1 and pdp2 to run audit simultaneously - */ - runAudit(integrityAudit, integrityAudit2); - waitStaleAndRun(integrityAudit3, integrityAudit4); - waitStaleAndRun(integrityAudit, integrityAudit2); - - /* - * These sequences may be intermingled, so we extract and compare one - * sequence at a time. - */ - - // only care about pdp1 & pdp3 in this sequence - verifyItemsInLog(logA, "pdp1", "pdp3", "pdp1"); - - // only care about pdp2 & pdp4 in this sequence - verifyItemsInLog(logB, "pdp2", "pdp4", "pdp2"); - - logger.info("testFourResourcesDifferentPus: Exiting"); - - } - - /* - * Tests designation logic when four resources are in play but one is not - * functioning. Designation should round robin among functioning resources - * only. - * - * Note: console.log must be examined to ascertain whether or not this test - * was successful. - */ - @Test - public void testFourResourcesOneDead() throws Exception { - - logger.info("testFourResourcesOneDead: Entering"); - - ExtractAppender logA = watch(debugLogger, START_AUDIT_RE); - - /* - * Start audit for pdp1. - */ - MyIntegrityAudit integrityAudit = makeAuditor("pdp1", A_SEQ_PU); - - /* - * Start audit for pdp2. - */ - MyIntegrityAudit integrityAudit2 = makeAuditor("pdp2", A_SEQ_PU); - - /* - * Populate DB for pdp3, which will simulate it having registered but - * then having died. - */ - new DbDAO("pdp3", A_SEQ_PU, makeProperties()).destroy(); - - /* - * Start audit for pdp4. - */ - MyIntegrityAudit integrityAudit4 = makeAuditor("pdp4", A_SEQ_PU); - - /* - * Sleep long enough to allow - * - * 1) pdp1 to run audit - * - * 2) Logic to detect that pdp1 is stale and designate pdp2 - * - * 3) pdp2 to run audit - * - * 4) Logic to detect that pdp2 is stale and designate pdp4 - * - * 5) pdp4 to run audit - * - * 6) Logic to detect that pdp4 is stale and designate pdp1 - * - * 7) pdp1 to run audit - * - * 8) Logic to detect that pdp1 is stale and designate pdp2 - * - * 7) pdp2 to run audit - */ - runAudit(integrityAudit); - waitStaleAndRun(integrityAudit2); - waitStaleAndRun(integrityAudit4); - waitStaleAndRun(integrityAudit); - waitStaleAndRun(integrityAudit2); - waitStaleAndRun(integrityAudit4); - - verifyItemsInLog(logA, "pdp1", "pdp2", "pdp4", "pdp1", "pdp2", "pdp4"); - - logger.info("testFourResourcesOneDead: Exiting"); - - } - - /* - * Tests designation logic when four resources are in play but only one is - * functioning. Designation should remain with sole functioning resource. - * - * Note: console.log must be examined to ascertain whether or not this test - * was successful. - */ - @Test - public void testFourResourcesThreeDead() throws Exception { - - logger.info("testFourResourcesThreeDead: Entering"); - - ExtractAppender logA = watch(debugLogger, START_AUDIT_RE); - - /* - * Populate DB for "pdp1", which will simulate it having registered but - * then having died. - */ - new DbDAO("pdp1", A_SEQ_PU, makeProperties()).destroy(); - - /* - * Populate DB for pdp2, which will simulate it having registered but - * then having died. - */ - new DbDAO("pdp2", A_SEQ_PU, makeProperties()).destroy(); - - /* - * Start audit for pdp3. - */ - MyIntegrityAudit integrityAudit3 = makeAuditor("pdp3", A_SEQ_PU); - - /* - * Populate DB for pdp4, which will simulate it having registered but - * then having died. - */ - new DbDAO("pdp4", A_SEQ_PU, makeProperties()).destroy(); - - /* - * Sleep long enough to allow - * - * 1) pdp3 to discover that all other designation candidates are stale - * - * 1) pdp3 to run audit - * - * 2) Logic to detect that no other nodes are available for designation - * - * 3) pdp3 to run audit again - */ - runAudit(integrityAudit3); - waitStaleAndRun(integrityAudit3); - - verifyItemsInLog(logA, "pdp3", "pdp3"); - - logger.info("testFourResourcesThreeDead: Exiting"); - - } - - /* - * Tests designation logic when the designated node dies and is no longer - * current - * - * Note: console.log must be examined to ascertain whether or not this test - * was successful. - */ - @Test - public void testDesignatedNodeDead() throws Exception { - logger.info("testDesignatedNodeDead: Entering"); - - ExtractAppender logA = watch(debugLogger, START_AUDIT_RE); - - /* - * Instantiate audit object for pdp1. - */ - MyIntegrityAudit integrityAudit = makeAuditor("pdp1", A_SEQ_PU); - - /* - * Start audit for pdp2. - */ - MyIntegrityAudit integrityAudit2 = makeAuditor("pdp2", A_SEQ_PU); - - /* - * Instantiate audit object for pdp3. - */ - MyIntegrityAudit integrityAudit3 = makeAuditor("pdp3", A_SEQ_PU); - - // Start audit on pdp1 - logger.info("testDesignatedNodeDead: Start audit on pdp1"); - runAudit(integrityAudit); - - // Start the auditing threads on other nodes. - logger.info("testDesignatedNodeDead: Start audit on pdp2"); - runAudit(integrityAudit2); - - // Kill audit on pdp1 - logger.info("testDesignatedNodeDead: Kill audit on pdp1"); - integrityAudit.stopAuditThread(); - - // Wait long enough for pdp1 to get stale and pdp2 to take over - waitStaleAndRun(integrityAudit2); - - // Start audit thread on pdp1 again. - logger.info("testDesignatedNodeDead: Start audit thread on pdp1 again."); - integrityAudit.startAuditThread(); - - // Wait long enough for pdp2 to complete its audit and get stale, at - // which point pdp3 should take over - logger.info( - "testDesignatedNodeDead: Wait long enough for pdp2 to complete its audit and get stale, at which point pdp3 should take over"); - waitStaleAndRun(integrityAudit3); - - // Kill audit on pdp3 - logger.info("testDesignatedNodeDead: Killing audit on pdp3"); - integrityAudit3.stopAuditThread(); - - // Wait long enough for pdp3 to get stale and pdp1 to take over - logger.info("testDesignatedNodeDead: Wait long enough for pdp3 to get stale and pdp1 to take over"); - waitStaleAndRun(integrityAudit); - - verifyItemsInLog(logA, "pdp1", "pdp2", "pdp3", "pdp1"); - - logger.info("testDesignatedNodeDead: Exiting"); - } + private static Logger logger = FlexLogger.getLogger(IntegrityAuditDesignationTest.class); + + /** + * Matches specified PDPs in the debug log. A regular expression matching the desired PDPs + * should be appended, followed by a right parenthesis. For example: + * + * <pre> + * <code>new ExtractAppender(START_AUDIT_RE_PREFIX + "pdp[124])") + * </code> + * </pre> + */ + private static final String START_AUDIT_RE_PREFIX = "Starting audit simulation for resourceName=("; + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + IntegrityAuditTestBase + .setUpBeforeClass(DEFAULT_DB_URL_PREFIX + IntegrityAuditDesignationTest.class.getSimpleName()); + } + + @AfterClass + public static void tearDownAfterClass() { + IntegrityAuditTestBase.tearDownAfterClass(); + } + + /** + * Set up before test cases. + */ + @Override + @Before + public void setUp() { + logger.info("setUp: Entering"); + + super.setUp(); + + logger.info("setUp: Exiting"); + } + + /** + * Tear down after test cases. + */ + @Override + @After + public void tearDown() { + logger.info("tearDown: Entering"); + + super.tearDown(); + + logger.info("tearDown: Exiting"); + + } + + /* + * Tests designation logic when only one functioning resource is in play. Designation should + * stay with single resource. + * + * Note: console.log must be examined to ascertain whether or not this test was successful. + */ + @Test + public void testOneResource() throws Exception { + + logger.info("testOneResource: Entering"); + + final ExtractAppender logA = watch(debugLogger, START_AUDIT_RE); + + MyIntegrityAudit integrityAudit = makeAuditor("pdp1", A_SEQ_PU); + + /* + * Wait for + * + * 1) pdp1 to run audit + * + * 2) Logic to detect that no other node is available for designation + * + * 3) pdp1 to run audit again + */ + runAudit(integrityAudit); + waitStaleAndRun(integrityAudit); + + logger.info("testOneResource: Stopping audit thread"); + integrityAudit.stopAuditThread(); + + verifyItemsInLog(logA, "pdp1"); + + /* + * Test fix for ONAPD2TD-783: Audit fails to run when application is restarted. + */ + integrityAudit.startAuditThread(); + + /* + * Sleep long enough to allow + * + * 1) pdp1 to run audit + * + * 2) Logic to detect that no other node is available for designation + * + * 3) pdp1 to run audit again + */ + runAudit(integrityAudit); + waitStaleAndRun(integrityAudit); + + verifyItemsInLog(logA, "pdp1"); + + logger.info("testOneResource: Exiting"); + + } + + /* + * Tests designation logic when two functioning resources are in play. Designation should + * alternate between resources. + * + * Note: console.log must be examined to ascertain whether or not this test was successful. A + * quick way of examining the log is to search for the string "audit simulation": + * + * As you can see from the "dbAuditSimulate" method, when it executes, it logs the + * "Starting audit simulation..." message and when it finishes, it logs the + * "Finished audit simulation..." message. By looking for these messages, you can verify that + * the audits are run by the proper resource. For example, when testFourResourcesOneDead is run, + * you should see a Starting.../Finished... sequence for "pdp1", followed by a + * Starting.../Finished... sequence for pdp2, followed by a Starting.../Finished... sequence for + * pdp4 (pdp3 is skipped as it's dead/hung), followed by a Starting.../Finished... sequence for + * "pdp1", etc. + */ + @Test + public void testTwoResources() throws Exception { + + logger.info("testTwoResources: Entering"); + + final ExtractAppender logA = watch(debugLogger, START_AUDIT_RE); + + /* + * Start audit for pdp1. + */ + MyIntegrityAudit integrityAudit = makeAuditor("pdp1", A_SEQ_PU); + + /* + * Start audit for pdp2. + */ + MyIntegrityAudit integrityAudit2 = makeAuditor("pdp2", A_SEQ_PU); + + /* + * Sleep long enough to allow + * + * 1) pdp1 to run audit + * + * 2) Logic to detect that pdp1 is stale and designate pdp2 + * + * 3) pdp2 to run audit + * + * 4) Logic to detect that pdp2 is stale and designate pdp1 + * + * 5) pdp1 to run audit + */ + runAudit(integrityAudit); + waitStaleAndRun(integrityAudit2); + waitStaleAndRun(integrityAudit); + + verifyItemsInLog(logA, "pdp1", "pdp2", "pdp1"); + + logger.info("testTwoResources: Exiting"); + + } + + /* + * Tests designation logic when two functioning resources are in play, each with different PUs. + * Audits for persistenceUnit and PU_B should run simultaneously. Designation should not + * alternate. + * + * Note: console.log must be examined to ascertain whether or not this test was successful. + */ + @Test + public void testTwoResourcesDifferentPus() throws Exception { + + logger.info("testTwoResourcesDifferentPus: Entering"); + + final ExtractAppender logA = watch(debugLogger, START_AUDIT_RE_PREFIX + "pdp1)"); + final ExtractAppender logB = watch(debugLogger, START_AUDIT_RE_PREFIX + "pdp2)"); + + /* + * Start audit for pdp1. + */ + MyIntegrityAudit integrityAudit = makeAuditor("pdp1", A_SEQ_PU); + + /* + * Start audit for pdp2. + */ + MyIntegrityAudit integrityAudit2 = makeAuditor("pdp2", B_SEQ_PU); + + /* + * Sleep long enough to allow + * + * 1) pdp1 and pdp2 to run audit simultaneously + * + * 2) Logic to detect that no other node is available for designation for either pdp1 or + * pdp2 + * + * 3) pdp1 and pdp2 to again run audit simultaneously + */ + runAudit(integrityAudit, integrityAudit2); + waitStaleAndRun(integrityAudit, integrityAudit2); + + verifyItemsInLog(logA, "pdp1", "pdp1"); + verifyItemsInLog(logB, "pdp2", "pdp2"); + + logger.info("testTwoResourcesDifferentPus: Exiting"); + + } + + /* + * Tests designation logic when two resources are in play but one of them is dead/hung. + * Designation should move to second resource but then get restored back to original resource + * when it's discovered that second resource is dead. + * + * Note: console.log must be examined to ascertain whether or not this test was successful. + */ + @Test + public void testTwoResourcesOneDead() throws Exception { + + logger.info("testTwoResourcesOneDead: Entering"); + + final ExtractAppender logA = watch(debugLogger, START_AUDIT_RE); + + /* + * Start audit for pdp1. + */ + MyIntegrityAudit integrityAudit = makeAuditor("pdp1", A_SEQ_PU); + + /* + * Populate DB for pdp2, which will simulate it having registered but then having died. + */ + new DbDAO("pdp2", A_SEQ_PU, makeProperties()).destroy(); + + /* + * Sleep long enough to allow + * + * 1) pdp1 to run audit + * + * 2) Logic to detect that other node, pdp2, is not available for designation + * + * 3) pdp1 to run audit again + */ + runAudit(integrityAudit); + waitStaleAndRun(integrityAudit); + + verifyItemsInLog(logA, "pdp1", "pdp1"); + + logger.info("testTwoResourcesOneDead: Exiting"); + + } + + /* + * Tests designation logic when three functioning resources are in play. Designation should + * round robin among resources. + * + * Note: console.log must be examined to ascertain whether or not this test was successful. + */ + @Test + public void testThreeResources() throws Exception { + + logger.info("testThreeResources: Entering"); + + final ExtractAppender logA = watch(debugLogger, START_AUDIT_RE); + + /* + * Start audit for pdp1. + */ + MyIntegrityAudit integrityAudit = makeAuditor("pdp1", A_SEQ_PU); + + /* + * Start audit for pdp2. + */ + MyIntegrityAudit integrityAudit2 = makeAuditor("pdp2", A_SEQ_PU); + + /* + * Start audit for pdp3. + */ + MyIntegrityAudit integrityAudit3 = makeAuditor("pdp3", A_SEQ_PU); + + /* + * Sleep long enough to allow + * + * 1) pdp1 to run audit + * + * 2) Logic to detect that pdp1 is stale and designate pdp2 + * + * 3) pdp2 to run audit + * + * 4) Logic to detect that pdp2 is stale and designate pdp3 + * + * 5) pdp3 to run audit + * + * 6) Logic to detect that pdp3 is stale and designate pdp1 + * + * 7) pdp1 to run audit + */ + runAudit(integrityAudit); + waitStaleAndRun(integrityAudit2); + waitStaleAndRun(integrityAudit3); + waitStaleAndRun(integrityAudit); + + verifyItemsInLog(logA, "pdp1", "pdp2", "pdp3", "pdp1"); + + logger.info("testThreeResources: Exiting"); + + } + + /* + * Tests designation logic when four functioning resources are in play, two with one PU, two + * with another. Audits for persistenceUnit and PU_B should run simultaneously. Designation + * should alternate between resources for each of the two persistence units. + * + * Note: console.log must be examined to ascertain whether or not this test was successful. + */ + @Test + public void testFourResourcesDifferentPus() throws Exception { + + logger.info("testFourResourcesDifferentPus: Entering"); + + final ExtractAppender logA = watch(debugLogger, START_AUDIT_RE_PREFIX + "pdp1|pdp3)"); + final ExtractAppender logB = watch(debugLogger, START_AUDIT_RE_PREFIX + "pdp2|pdp4)"); + + /* + * Start audit for "pdp1", testPU. + */ + MyIntegrityAudit integrityAudit = makeAuditor("pdp1", A_SEQ_PU); + + /* + * Start audit for pdp2, integrityAuditPU. + */ + MyIntegrityAudit integrityAudit2 = makeAuditor("pdp2", B_SEQ_PU); + + /* + * Start audit for pdp3, testPU. + */ + MyIntegrityAudit integrityAudit3 = makeAuditor("pdp3", A_SEQ_PU); + + /* + * Start audit for pdp4, integrityAuditPU. + */ + MyIntegrityAudit integrityAudit4 = makeAuditor("pdp4", B_SEQ_PU); + + /* + * Sleep long enough to allow + * + * 1) pdp1 and pdp2 to run audit simultaneously + * + * 2) Logic to detect that pdp1 and pdp2 are stale and designate pdp3 (one's counterpart) + * and pdp4 (two's counterpart) + * + * 3) pdp3 and pdp4 to run audit simultaneously + * + * 4) Logic to detect that pdp3 and pdp4 are stale and designate pdp1 (three's counterpart) + * and pdp2 (four's counterpart) + * + * 5) pdp1 and pdp2 to run audit simultaneously + */ + runAudit(integrityAudit, integrityAudit2); + waitStaleAndRun(integrityAudit3, integrityAudit4); + waitStaleAndRun(integrityAudit, integrityAudit2); + + /* + * These sequences may be intermingled, so we extract and compare one sequence at a time. + */ + + // only care about pdp1 & pdp3 in this sequence + verifyItemsInLog(logA, "pdp1", "pdp3", "pdp1"); + + // only care about pdp2 & pdp4 in this sequence + verifyItemsInLog(logB, "pdp2", "pdp4", "pdp2"); + + logger.info("testFourResourcesDifferentPus: Exiting"); + + } + + /* + * Tests designation logic when four resources are in play but one is not functioning. + * Designation should round robin among functioning resources only. + * + * Note: console.log must be examined to ascertain whether or not this test was successful. + */ + @Test + public void testFourResourcesOneDead() throws Exception { + + logger.info("testFourResourcesOneDead: Entering"); + + final ExtractAppender logA = watch(debugLogger, START_AUDIT_RE); + + /* + * Start audit for pdp1. + */ + MyIntegrityAudit integrityAudit = makeAuditor("pdp1", A_SEQ_PU); + + /* + * Start audit for pdp2. + */ + MyIntegrityAudit integrityAudit2 = makeAuditor("pdp2", A_SEQ_PU); + + /* + * Populate DB for pdp3, which will simulate it having registered but then having died. + */ + new DbDAO("pdp3", A_SEQ_PU, makeProperties()).destroy(); + + /* + * Start audit for pdp4. + */ + MyIntegrityAudit integrityAudit4 = makeAuditor("pdp4", A_SEQ_PU); + + /* + * Sleep long enough to allow + * + * 1) pdp1 to run audit + * + * 2) Logic to detect that pdp1 is stale and designate pdp2 + * + * 3) pdp2 to run audit + * + * 4) Logic to detect that pdp2 is stale and designate pdp4 + * + * 5) pdp4 to run audit + * + * 6) Logic to detect that pdp4 is stale and designate pdp1 + * + * 7) pdp1 to run audit + * + * 8) Logic to detect that pdp1 is stale and designate pdp2 + * + * 7) pdp2 to run audit + */ + runAudit(integrityAudit); + waitStaleAndRun(integrityAudit2); + waitStaleAndRun(integrityAudit4); + waitStaleAndRun(integrityAudit); + waitStaleAndRun(integrityAudit2); + waitStaleAndRun(integrityAudit4); + + verifyItemsInLog(logA, "pdp1", "pdp2", "pdp4", "pdp1", "pdp2", "pdp4"); + + logger.info("testFourResourcesOneDead: Exiting"); + + } + + /* + * Tests designation logic when four resources are in play but only one is functioning. + * Designation should remain with sole functioning resource. + * + * Note: console.log must be examined to ascertain whether or not this test was successful. + */ + @Test + public void testFourResourcesThreeDead() throws Exception { + + logger.info("testFourResourcesThreeDead: Entering"); + + final ExtractAppender logA = watch(debugLogger, START_AUDIT_RE); + + /* + * Populate DB for "pdp1", which will simulate it having registered but then having died. + */ + new DbDAO("pdp1", A_SEQ_PU, makeProperties()).destroy(); + + /* + * Populate DB for pdp2, which will simulate it having registered but then having died. + */ + new DbDAO("pdp2", A_SEQ_PU, makeProperties()).destroy(); + + /* + * Start audit for pdp3. + */ + MyIntegrityAudit integrityAudit3 = makeAuditor("pdp3", A_SEQ_PU); + + /* + * Populate DB for pdp4, which will simulate it having registered but then having died. + */ + new DbDAO("pdp4", A_SEQ_PU, makeProperties()).destroy(); + + /* + * Sleep long enough to allow + * + * 1) pdp3 to discover that all other designation candidates are stale + * + * 1) pdp3 to run audit + * + * 2) Logic to detect that no other nodes are available for designation + * + * 3) pdp3 to run audit again + */ + runAudit(integrityAudit3); + waitStaleAndRun(integrityAudit3); + + verifyItemsInLog(logA, "pdp3", "pdp3"); + + logger.info("testFourResourcesThreeDead: Exiting"); + + } + + /* + * Tests designation logic when the designated node dies and is no longer current + * + * Note: console.log must be examined to ascertain whether or not this test was successful. + */ + @Test + public void testDesignatedNodeDead() throws Exception { + logger.info("testDesignatedNodeDead: Entering"); + + final ExtractAppender logA = watch(debugLogger, START_AUDIT_RE); + + /* + * Instantiate audit object for pdp1. + */ + final MyIntegrityAudit integrityAudit = makeAuditor("pdp1", A_SEQ_PU); + + /* + * Start audit for pdp2. + */ + final MyIntegrityAudit integrityAudit2 = makeAuditor("pdp2", A_SEQ_PU); + + /* + * Instantiate audit object for pdp3. + */ + final MyIntegrityAudit integrityAudit3 = makeAuditor("pdp3", A_SEQ_PU); + + // Start audit on pdp1 + logger.info("testDesignatedNodeDead: Start audit on pdp1"); + runAudit(integrityAudit); + + // Start the auditing threads on other nodes. + logger.info("testDesignatedNodeDead: Start audit on pdp2"); + runAudit(integrityAudit2); + + // Kill audit on pdp1 + logger.info("testDesignatedNodeDead: Kill audit on pdp1"); + integrityAudit.stopAuditThread(); + + // Wait long enough for pdp1 to get stale and pdp2 to take over + waitStaleAndRun(integrityAudit2); + + // Start audit thread on pdp1 again. + logger.info("testDesignatedNodeDead: Start audit thread on pdp1 again."); + integrityAudit.startAuditThread(); + + // Wait long enough for pdp2 to complete its audit and get stale, at + // which point pdp3 should take over + logger.info( + "testDesignatedNodeDead: Wait long enough for pdp2 to complete its audit and get stale, at which point" + + " pdp3 should take over"); + waitStaleAndRun(integrityAudit3); + + // Kill audit on pdp3 + logger.info("testDesignatedNodeDead: Killing audit on pdp3"); + integrityAudit3.stopAuditThread(); + + // Wait long enough for pdp3 to get stale and pdp1 to take over + logger.info("testDesignatedNodeDead: Wait long enough for pdp3 to get stale and pdp1 to take over"); + waitStaleAndRun(integrityAudit); + + verifyItemsInLog(logA, "pdp1", "pdp2", "pdp3", "pdp1"); + + logger.info("testDesignatedNodeDead: Exiting"); + } } diff --git a/integrity-audit/src/test/java/org/onap/policy/common/ia/IntegrityAuditTest.java b/integrity-audit/src/test/java/org/onap/policy/common/ia/IntegrityAuditTest.java index 344ac34e..5adbb561 100644 --- a/integrity-audit/src/test/java/org/onap/policy/common/ia/IntegrityAuditTest.java +++ b/integrity-audit/src/test/java/org/onap/policy/common/ia/IntegrityAuditTest.java @@ -20,53 +20,52 @@ package org.onap.policy.common.ia; -import static org.junit.Assert.*; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import java.util.Properties; import org.junit.Test; -import org.onap.policy.common.ia.IntegrityAudit; -import org.onap.policy.common.ia.IntegrityAuditProperties; public class IntegrityAuditTest { - @Test - /** - * Test if we can access the updated bad params outside of the parmsAreBad method - */ - public void parmsAreBadTest() { - // Try with 2 null params - StringBuilder badParams = new StringBuilder(); - IntegrityAudit.parmsAreBad(null, "something", null, badParams); - - assertFalse("".equals(badParams.toString())); - assertTrue(badParams.toString().contains("resourceName")); - assertTrue(badParams.toString().contains("properties")); - - // Try with 1 null params - badParams = new StringBuilder(); - Properties props = new Properties(); - props.put(IntegrityAuditProperties.DB_DRIVER, "test_db_driver"); - IntegrityAudit.parmsAreBad(null, "something", props, badParams); - - assertFalse("".equals(badParams.toString())); - assertTrue(badParams.toString().contains("resourceName")); - assertFalse(badParams.toString().contains("properties")); - - // Try with 0 null params - badParams = new StringBuilder(); - IntegrityAudit.parmsAreBad("someting", "something", props, badParams); - assertFalse("".equals(badParams.toString())); - assertFalse(badParams.toString().contains("resourceName")); - assertFalse(badParams.toString().contains("properties")); - - // Try with invalid node type - props.put(IntegrityAuditProperties.NODE_TYPE, "bogus"); - badParams = new StringBuilder(); - IntegrityAudit.parmsAreBad("someting", "something", props, badParams); - assertFalse("".equals(badParams.toString())); - assertTrue(badParams.toString().contains("nodeType")); + @Test + /** + * Test if we can access the updated bad params outside of the parmsAreBad method. + */ + public void parmsAreBadTest() { + // Try with 2 null params + StringBuilder badParams = new StringBuilder(); + IntegrityAudit.parmsAreBad(null, "something", null, badParams); - } + assertFalse("".equals(badParams.toString())); + assertTrue(badParams.toString().contains("resourceName")); + assertTrue(badParams.toString().contains("properties")); + + // Try with 1 null params + badParams = new StringBuilder(); + Properties props = new Properties(); + props.put(IntegrityAuditProperties.DB_DRIVER, "test_db_driver"); + IntegrityAudit.parmsAreBad(null, "something", props, badParams); + + assertFalse("".equals(badParams.toString())); + assertTrue(badParams.toString().contains("resourceName")); + assertFalse(badParams.toString().contains("properties")); + + // Try with 0 null params + badParams = new StringBuilder(); + IntegrityAudit.parmsAreBad("someting", "something", props, badParams); + assertFalse("".equals(badParams.toString())); + assertFalse(badParams.toString().contains("resourceName")); + assertFalse(badParams.toString().contains("properties")); + + // Try with invalid node type + props.put(IntegrityAuditProperties.NODE_TYPE, "bogus"); + badParams = new StringBuilder(); + IntegrityAudit.parmsAreBad("someting", "something", props, badParams); + assertFalse("".equals(badParams.toString())); + assertTrue(badParams.toString().contains("nodeType")); + + } } diff --git a/integrity-audit/src/test/java/org/onap/policy/common/ia/IntegrityAuditTestBase.java b/integrity-audit/src/test/java/org/onap/policy/common/ia/IntegrityAuditTestBase.java index e30c5631..afbcc452 100644 --- a/integrity-audit/src/test/java/org/onap/policy/common/ia/IntegrityAuditTestBase.java +++ b/integrity-audit/src/test/java/org/onap/policy/common/ia/IntegrityAuditTestBase.java @@ -23,6 +23,9 @@ package org.onap.policy.common.ia; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.Logger; + import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; @@ -47,587 +50,560 @@ import org.onap.policy.common.utils.jpa.EntityTransCloser; import org.onap.policy.common.utils.test.log.logback.ExtractAppender; import org.slf4j.LoggerFactory; -import ch.qos.logback.classic.Level; -import ch.qos.logback.classic.Logger; - /** - * All JUnits are designed to run in the local development environment where - * they have write privileges and can execute time-sensitive tasks. - * <p/> - * Many of the test verification steps are performed by scanning for items - * written to the log file. Rather than actually scan the log file, an - * {@link ExtractAppender} is used to monitor events that are logged and extract - * relevant items. In order to attach the appender to the debug log, it assumes - * that the debug log is a <i>logback</i> Logger configured per EELF. - * <p/> - * These tests use a temporary, in-memory DB, which is dropped once the tests - * complete. + * All JUnits are designed to run in the local development environment where they have write + * privileges and can execute time-sensitive tasks. + * + * <p>Many of the test verification steps are performed by scanning for items written to the log + * file. Rather than actually scan the log file, an {@link ExtractAppender} is used to monitor + * events that are logged and extract relevant items. In order to attach the appender to the debug + * log, it assumes that the debug log is a <i>logback</i> Logger configured per EELF. + * + * <p>These tests use a temporary, in-memory DB, which is dropped once the tests complete. */ public class IntegrityAuditTestBase { - /** - * Root of the debug logger, as defined in the logback-test.xml. - */ - protected static final Logger debugLogger = (Logger) LoggerFactory.getLogger("com.att.eelf.debug"); - - /** - * Root of the error logger, as defined in the logback-test.xml. - */ - protected static final Logger errorLogger = (Logger) LoggerFactory.getLogger("com.att.eelf.error"); - - /** - * Directory containing the log files. - */ - private static final String LOG_DIR = "testingLogs/common-modules/integrity-audit"; - - /** - * Max time, in milliseconds, to wait for a latch to be triggered. - */ - protected static final long WAIT_MS = 5000l; - - /** - * Milliseconds that auditor should sleep between audit steps. - */ - protected static final long SLEEP_INTERVAL_MS = 2l; - - /** - * Milliseconds that auditor should sleep when an audit completes. - */ - protected static final long COMPLETION_INTERVAL_MS = 5l; - - /** - * Milliseconds that an entire audit-simulation cycles takes. - */ - protected static final long AUDIT_SIMULATION_MS = SLEEP_INTERVAL_MS * AuditThread.AUDIT_SIMULATION_ITERATIONS; - - /** - * Milliseconds that it takes for an auditor's last update to become stale. - * Includes a 1ms fudge factor. - */ - protected static final long STALE_MS = 1 + 2 * Math.max(COMPLETION_INTERVAL_MS, AUDIT_SIMULATION_MS); - - /** - * Milliseconds that the db-audit should wait between makings updates. - */ - private static final long DB_AUDIT_UPDATE_MS = 10l; - - /** - * Milliseconds that the db-audit should sleep between cycles. - */ - private static final long DB_AUDIT_SLEEP_MS = 3l; - - public static final String DEFAULT_DB_URL_PREFIX = "jdbc:h2:mem:"; - - protected static final String dbDriver = "org.h2.Driver"; - protected static final String dbUser = "testu"; - protected static final String dbPwd = "testp"; - protected static final String siteName = "SiteA"; - protected static final String nodeType = "pdp_xacml"; - - // will be defined by the test *Classes* - protected static String dbUrl; - - /** - * Persistence unit for PDP sequence A. - */ - protected static final String A_SEQ_PU = "testPU"; - - /** - * Persistence unit for PDP sequence B. - */ - protected static final String B_SEQ_PU = "integrityAuditPU"; - - /** - * Matches the start of an audit for arbitrary PDPs in the debug log. - */ - protected static final String START_AUDIT_RE = "Starting audit simulation for resourceName=([^,]*)"; - - /** - * Properties to be used in all tests. - */ - protected static Properties properties; - - /** - * Entity manager factory pointing to the in-memory DB for A_SEQ_PU. - */ - protected static EntityManagerFactory emf; - - /** - * Entity manager factory pointing to the in-memory DB associated with emf. - */ - protected static EntityManager em; - - /** - * Saved debug logger level, to be restored once all tests complete. - */ - private static Level savedDebugLevel; - - /** - * Saved error logger level, to be restored once all tests complete. - */ - private static Level savedErrorLevel; - - /** - * Saved audit sleep interval, to be restored once all tests complete. - */ - private static long savedSleepIntervalMs; - - /** - * Saved audit completion interval, to be restored once all tests complete. - */ - private static long savedCompletionIntervalMs; - - /** - * Saved db audit update time, to be restored once all tests complete. - */ - private static long savedDbAuditUpdateMs; - - /** - * Saved db audit sleep time, to be restored once all tests complete. - */ - private static long savedDbAuditSleepMs; - - /** - * List of auditors whose threads must be stopped when a given test case - * ends. - */ - private List<MyIntegrityAudit> auditors; - - /** - * List of appenders that must be removed from loggers when a given test - * case ends. - */ - private List<LogApp> appenders; - - /** - * Saves current configuration information and then sets new values. - * - * @param dbDriver - * the name of the DB Driver class - * @param dbUrl - * the URL to the DB - * @throws IOException - * @throws Exception - */ - protected static void setUpBeforeClass(String dbUrl) throws IOException { - - // truncate the logs - new FileOutputStream(LOG_DIR + "/audit.log").close(); - new FileOutputStream(LOG_DIR + "/debug.log").close(); - new FileOutputStream(LOG_DIR + "/error.log").close(); - new FileOutputStream(LOG_DIR + "/metrics.log").close(); - - IntegrityAuditTestBase.dbUrl = dbUrl; - - // save data that we have to restore at the end of the test - savedDebugLevel = debugLogger.getLevel(); - savedErrorLevel = errorLogger.getLevel(); - savedSleepIntervalMs = AuditThread.getAuditThreadSleepIntervalMillis(); - savedCompletionIntervalMs = AuditThread.getAuditCompletionIntervalMillis(); - savedDbAuditUpdateMs = DbAudit.getDbAuditUpdateMillis(); - savedDbAuditSleepMs = DbAudit.getDbAuditSleepMillis(); - - AuditThread.setAuditThreadSleepIntervalMillis(SLEEP_INTERVAL_MS); - AuditThread.setAuditCompletionIntervalMillis(COMPLETION_INTERVAL_MS); - - DbAudit.setDbAuditUpdateMillis(DB_AUDIT_UPDATE_MS); - DbAudit.setDbAuditSleepMillis(DB_AUDIT_SLEEP_MS); - - IntegrityAudit.setUnitTesting(true); - - properties = new Properties(); - properties.put(IntegrityAuditProperties.DB_DRIVER, dbDriver); - properties.put(IntegrityAuditProperties.DB_URL, dbUrl); - properties.put(IntegrityAuditProperties.DB_USER, dbUser); - properties.put(IntegrityAuditProperties.DB_PWD, dbPwd); - properties.put(IntegrityAuditProperties.SITE_NAME, siteName); - properties.put(IntegrityAuditProperties.NODE_TYPE, nodeType); - - emf = Persistence.createEntityManagerFactory(A_SEQ_PU, makeProperties()); - - // keep this open so the in-memory DB stays around until all tests are - // done - em = emf.createEntityManager(); - - debugLogger.setLevel(Level.DEBUG); - errorLogger.setLevel(Level.ERROR); - } - - /** - * Restores the configuration to what it was before the test. - */ - protected static void tearDownAfterClass() { - AuditThread.setAuditThreadSleepIntervalMillis(savedSleepIntervalMs); - AuditThread.setAuditCompletionIntervalMillis(savedCompletionIntervalMs); - - DbAudit.setDbAuditUpdateMillis(savedDbAuditUpdateMs); - DbAudit.setDbAuditSleepMillis(savedDbAuditSleepMs); - - IntegrityAudit.setUnitTesting(false); - - debugLogger.setLevel(savedDebugLevel); - errorLogger.setLevel(savedErrorLevel); - - // this should result in the in-memory DB being deleted - em.close(); - emf.close(); - } - - /** - * Sets up for a test, which includes deleting all records from the - * IntegrityAuditEntity table. - */ - protected void setUp() { - auditors = new LinkedList<>(); - appenders = new LinkedList<>(); - - properties.put(IntegrityAuditProperties.AUDIT_PERIOD_MILLISECONDS, String.valueOf(SLEEP_INTERVAL_MS)); - - // Clean up the DB - try (EntityTransCloser etc = new EntityTransCloser(em.getTransaction())) { - EntityTransaction et = etc.getTransation(); - - em.createQuery("Delete from IntegrityAuditEntity").executeUpdate(); - - // commit transaction - et.commit(); - } - } - - /** - * Cleans up after a test, removing any ExtractAppenders from the logger and - * stopping any AuditThreads. - */ - protected void tearDown() { - for (LogApp p : appenders) { - p.detach(); - } - - for (MyIntegrityAudit p : auditors) { - p.stopAuditThread(); - } - } - - /** - * - * @param properties - * @param persistenceUnit - * @param tableName - */ - public void truncateTable(Properties properties, String persistenceUnit, String tableName) { - - try (EntityMgrFactoryCloser emfc = new EntityMgrFactoryCloser( - Persistence.createEntityManagerFactory(persistenceUnit, properties)); - EntityMgrCloser emc = new EntityMgrCloser(emfc.getFactory().createEntityManager()); - EntityTransCloser etc = new EntityTransCloser(emc.getManager().getTransaction())) { - - EntityManager em = emc.getManager(); - EntityTransaction et = etc.getTransation(); - - // Clean up the DB - em.createQuery("Delete from " + tableName).executeUpdate(); - - // commit transaction - et.commit(); - } - } - - /** - * Verifies that items appear within the log, in order. A given item may - * appear more than once. In addition, the log may contain extra items; - * those are ignored. - * - * @param textre - * regular expression used to extract an item from a line in the - * log. The first "capture" group of the regular expression is - * assumed to contain the extracted item - * @param items - * items that should be matched by the items extracted from the - * log, in order - * @throws IOException - * @throws AssertionError - * if the desired items were not all found - */ - protected void verifyItemsInLog(ExtractAppender app, String... items) throws IOException { - - Iterator<String> it = new ArrayList<>(Arrays.asList(items)).iterator(); - if (!it.hasNext()) { - return; - } - - String expected = it.next(); - String last = null; - - for (String rName : app.getExtracted()) { - if (rName.equals(expected)) { - if (!it.hasNext()) { - // matched all of the items - return; - } - - last = expected; - expected = it.next(); - - } else if (!rName.equals(last)) { - List<String> remaining = getRemaining(expected, it); - fail("missing items " + remaining + ", but was: " + rName); - } - } - - List<String> remaining = getRemaining(expected, it); - assertTrue("missing items " + remaining, remaining.isEmpty()); - } - - /** - * Gets the remaining items from an iterator - * - * @param current - * the current item, to be included within the list - * @param it - * iterator from which to get the remaining items - * @return a list of the remaining items - */ - private LinkedList<String> getRemaining(String current, Iterator<String> it) { - LinkedList<String> remaining = new LinkedList<>(); - remaining.add(current); - - while (it.hasNext()) { - remaining.add(it.next()); - } - return remaining; - } - - /** - * Waits for a thread to stop. If the thread doesn't complete in the - * allotted time, then it interrupts it and waits again. - * - * @param auditor - * the thread for which to wait - * @return {@code true} if the thread stopped, {@code false} otherwise - */ - public boolean waitThread(MyIntegrityAudit auditor) { - if (auditor != null) { - try { - auditor.interrupt(); - - if (!auditor.joinAuditThread(WAIT_MS)) { - System.out.println("failed to stop audit thread"); - return false; - } - - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - } - - return true; - } - - /** - * Makes a new auditor. - * - * @param resourceName2 - * @param persistenceUnit2 - * @return a new auditor - * @throws Exception - */ - protected MyIntegrityAudit makeAuditor(String resourceName2, String persistenceUnit2) throws Exception { - return new MyIntegrityAudit(resourceName2, persistenceUnit2, makeProperties()); - } - - /** - * Watches for patterns in a logger by attaching a ExtractAppender to it. - * - * @param logger - * the logger to watch - * @param regex - * regular expression used to extract relevant text - * @return a new appender - */ - protected ExtractAppender watch(Logger logger, String regex) { - ExtractAppender app = new ExtractAppender(regex); - appenders.add(new LogApp(logger, app)); - - return app; - } - - /** - * Makes a new Property set that's a clone of {@link #properties}. - * - * @return a new Property set containing all of a copy of all of the - * {@link #properties} - */ - protected static Properties makeProperties() { - Properties props = new Properties(); - props.putAll(properties); - return props; - } - - /** - * Waits for data to become stale and then runs an audit on several auditors - * in parallel. - * - * @param auditors - * @throws InterruptedException - */ - protected void waitStaleAndRun(MyIntegrityAudit... auditors) throws InterruptedException { - waitStale(); - runAudit(auditors); - } - - /** - * Runs an audit on several auditors in parallel. - * - * @param auditors - * @throws InterruptedException - */ - protected void runAudit(MyIntegrityAudit... auditors) throws InterruptedException { - - // start an audit cycle on each auditor - List<CountDownLatch> latches = new ArrayList<>(auditors.length); - for (MyIntegrityAudit p : auditors) { - latches.add(p.startAudit()); - } - - // wait for each auditor to complete its cycle - for (CountDownLatch latch : latches) { - waitLatch(latch); - } - } - - /** - * Waits for a latch to reach zero. - * - * @param latch - * @throws InterruptedException - * @throws AssertionError - * if the latch did not reach zero in the allotted time - */ - protected void waitLatch(CountDownLatch latch) throws InterruptedException { - assertTrue(latch.await(WAIT_MS, TimeUnit.SECONDS)); - } - - /** - * Sleep a bit so that the currently designated pdp becomes stale. - * - * @throws InterruptedException - */ - protected void waitStale() throws InterruptedException { - Thread.sleep(STALE_MS); - } - - /** - * Tracks which appender has been added to a logger. - */ - private static class LogApp { - private final Logger logger; - private final ExtractAppender appender; - - public LogApp(Logger logger, ExtractAppender appender) { - this.logger = logger; - this.appender = appender; - - logger.addAppender(appender); - - appender.start(); - } - - public void detach() { - logger.detachAppender(appender); - } - } - - /** - * Manages audits by inserting latches into a queue for the AuditThread to - * count. - */ - protected class MyIntegrityAudit extends IntegrityAudit { - - /** - * Queue from which the AuditThread will take latches. - */ - private BlockingQueue<CountDownLatch> queue = null; - - /** - * Constructs an auditor and starts the AuditThread. - * - * @param resourceName - * @param persistenceUnit - * @param properties - * @throws Exception - */ - public MyIntegrityAudit(String resourceName, String persistenceUnit, Properties properties) throws Exception { - super(resourceName, persistenceUnit, properties); - - auditors.add(this); - - startAuditThread(); - } - - /** - * Interrupts the AuditThread. - */ - public void interrupt() { - super.stopAuditThread(); - } - - /** - * Triggers an audit by adding a latch to the queue. - * - * @return the latch that was added - * @throws InterruptedException - */ - public CountDownLatch startAudit() throws InterruptedException { - CountDownLatch latch = new CountDownLatch(1); - queue.add(latch); - - return latch; - } - - /** - * Starts a new AuditThread. Creates a new latch queue and associates it - * with the thread. - */ - @Override - public final void startAuditThread() throws IntegrityAuditException { - if (queue != null) { - // queue up a bogus latch, in case a thread is still running - queue.add(new CountDownLatch(1) { - @Override - public void countDown() { - throw new RuntimeException("auditor has multiple threads"); - } - }); - } - - queue = new LinkedBlockingQueue<>(); - - if (super.startAuditThread(queue)) { - // wait for the thread to start - CountDownLatch latch = new CountDownLatch(1); - queue.add(latch); - - try { - waitLatch(latch); - - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw new IntegrityAuditException(e); - } - } - } - - /** - * Stops the AuditThread and waits for it to stop. - * - * @throws AssertionError - * if the thread is still running - */ - @Override - public void stopAuditThread() { - super.stopAuditThread(); - - assertTrue(waitThread(this)); - } - } + /** + * Root of the debug logger, as defined in the logback-test.xml. + */ + protected static final Logger debugLogger = (Logger) LoggerFactory.getLogger("com.att.eelf.debug"); + + /** + * Root of the error logger, as defined in the logback-test.xml. + */ + protected static final Logger errorLogger = (Logger) LoggerFactory.getLogger("com.att.eelf.error"); + + /** + * Directory containing the log files. + */ + private static final String LOG_DIR = "testingLogs/common-modules/integrity-audit"; + + /** + * Max time, in milliseconds, to wait for a latch to be triggered. + */ + protected static final long WAIT_MS = 5000L; + + /** + * Milliseconds that auditor should sleep between audit steps. + */ + protected static final long SLEEP_INTERVAL_MS = 2L; + + /** + * Milliseconds that auditor should sleep when an audit completes. + */ + protected static final long COMPLETION_INTERVAL_MS = 5L; + + /** + * Milliseconds that an entire audit-simulation cycles takes. + */ + protected static final long AUDIT_SIMULATION_MS = SLEEP_INTERVAL_MS * AuditThread.AUDIT_SIMULATION_ITERATIONS; + + /** + * Milliseconds that it takes for an auditor's last update to become stale. Includes a 1ms fudge + * factor. + */ + protected static final long STALE_MS = 1 + 2 * Math.max(COMPLETION_INTERVAL_MS, AUDIT_SIMULATION_MS); + + /** + * Milliseconds that the db-audit should wait between makings updates. + */ + private static final long DB_AUDIT_UPDATE_MS = 10L; + + /** + * Milliseconds that the db-audit should sleep between cycles. + */ + private static final long DB_AUDIT_SLEEP_MS = 3L; + + public static final String DEFAULT_DB_URL_PREFIX = "jdbc:h2:mem:"; + + protected static final String dbDriver = "org.h2.Driver"; + protected static final String dbUser = "testu"; + protected static final String dbPwd = "testp"; + protected static final String siteName = "SiteA"; + protected static final String nodeType = "pdp_xacml"; + + // will be defined by the test *Classes* + protected static String dbUrl; + + /** + * Persistence unit for PDP sequence A. + */ + protected static final String A_SEQ_PU = "testPU"; + + /** + * Persistence unit for PDP sequence B. + */ + protected static final String B_SEQ_PU = "integrityAuditPU"; + + /** + * Matches the start of an audit for arbitrary PDPs in the debug log. + */ + protected static final String START_AUDIT_RE = "Starting audit simulation for resourceName=([^,]*)"; + + /** + * Properties to be used in all tests. + */ + protected static Properties properties; + + /** + * Entity manager factory pointing to the in-memory DB for A_SEQ_PU. + */ + protected static EntityManagerFactory emf; + + /** + * Entity manager factory pointing to the in-memory DB associated with emf. + */ + protected static EntityManager em; + + /** + * Saved debug logger level, to be restored once all tests complete. + */ + private static Level savedDebugLevel; + + /** + * Saved error logger level, to be restored once all tests complete. + */ + private static Level savedErrorLevel; + + /** + * Saved audit sleep interval, to be restored once all tests complete. + */ + private static long savedSleepIntervalMs; + + /** + * Saved audit completion interval, to be restored once all tests complete. + */ + private static long savedCompletionIntervalMs; + + /** + * Saved db audit update time, to be restored once all tests complete. + */ + private static long savedDbAuditUpdateMs; + + /** + * Saved db audit sleep time, to be restored once all tests complete. + */ + private static long savedDbAuditSleepMs; + + /** + * List of auditors whose threads must be stopped when a given test case ends. + */ + private List<MyIntegrityAudit> auditors; + + /** + * List of appenders that must be removed from loggers when a given test case ends. + */ + private List<LogApp> appenders; + + /** + * Saves current configuration information and then sets new values. + * + * @param dbDriver the name of the DB Driver class + * @param dbUrl the URL to the DB + * @throws IOException if an IO error occurs + */ + protected static void setUpBeforeClass(String dbUrl) throws IOException { + + // truncate the logs + new FileOutputStream(LOG_DIR + "/audit.log").close(); + new FileOutputStream(LOG_DIR + "/debug.log").close(); + new FileOutputStream(LOG_DIR + "/error.log").close(); + new FileOutputStream(LOG_DIR + "/metrics.log").close(); + + IntegrityAuditTestBase.dbUrl = dbUrl; + + // save data that we have to restore at the end of the test + savedDebugLevel = debugLogger.getLevel(); + savedErrorLevel = errorLogger.getLevel(); + savedSleepIntervalMs = AuditThread.getAuditThreadSleepIntervalMillis(); + savedCompletionIntervalMs = AuditThread.getAuditCompletionIntervalMillis(); + savedDbAuditUpdateMs = DbAudit.getDbAuditUpdateMillis(); + savedDbAuditSleepMs = DbAudit.getDbAuditSleepMillis(); + + AuditThread.setAuditThreadSleepIntervalMillis(SLEEP_INTERVAL_MS); + AuditThread.setAuditCompletionIntervalMillis(COMPLETION_INTERVAL_MS); + + DbAudit.setDbAuditUpdateMillis(DB_AUDIT_UPDATE_MS); + DbAudit.setDbAuditSleepMillis(DB_AUDIT_SLEEP_MS); + + IntegrityAudit.setUnitTesting(true); + + properties = new Properties(); + properties.put(IntegrityAuditProperties.DB_DRIVER, dbDriver); + properties.put(IntegrityAuditProperties.DB_URL, dbUrl); + properties.put(IntegrityAuditProperties.DB_USER, dbUser); + properties.put(IntegrityAuditProperties.DB_PWD, dbPwd); + properties.put(IntegrityAuditProperties.SITE_NAME, siteName); + properties.put(IntegrityAuditProperties.NODE_TYPE, nodeType); + + emf = Persistence.createEntityManagerFactory(A_SEQ_PU, makeProperties()); + + // keep this open so the in-memory DB stays around until all tests are + // done + em = emf.createEntityManager(); + + debugLogger.setLevel(Level.DEBUG); + errorLogger.setLevel(Level.ERROR); + } + + /** + * Restores the configuration to what it was before the test. + */ + protected static void tearDownAfterClass() { + AuditThread.setAuditThreadSleepIntervalMillis(savedSleepIntervalMs); + AuditThread.setAuditCompletionIntervalMillis(savedCompletionIntervalMs); + + DbAudit.setDbAuditUpdateMillis(savedDbAuditUpdateMs); + DbAudit.setDbAuditSleepMillis(savedDbAuditSleepMs); + + IntegrityAudit.setUnitTesting(false); + + debugLogger.setLevel(savedDebugLevel); + errorLogger.setLevel(savedErrorLevel); + + // this should result in the in-memory DB being deleted + em.close(); + emf.close(); + } + + /** + * Sets up for a test, which includes deleting all records from the IntegrityAuditEntity table. + */ + protected void setUp() { + auditors = new LinkedList<>(); + appenders = new LinkedList<>(); + + properties.put(IntegrityAuditProperties.AUDIT_PERIOD_MILLISECONDS, String.valueOf(SLEEP_INTERVAL_MS)); + + // Clean up the DB + try (EntityTransCloser etc = new EntityTransCloser(em.getTransaction())) { + EntityTransaction et = etc.getTransation(); + + em.createQuery("Delete from IntegrityAuditEntity").executeUpdate(); + + // commit transaction + et.commit(); + } + } + + /** + * Cleans up after a test, removing any ExtractAppenders from the logger and stopping any + * AuditThreads. + */ + protected void tearDown() { + for (LogApp p : appenders) { + p.detach(); + } + + for (MyIntegrityAudit p : auditors) { + p.stopAuditThread(); + } + } + + /** + * Truncate the table. + * + * @param properties the properties + * @param persistenceUnit the persistence unit + * @param tableName the name of the table + */ + public void truncateTable(Properties properties, String persistenceUnit, String tableName) { + + try (EntityMgrFactoryCloser emfc = + new EntityMgrFactoryCloser(Persistence.createEntityManagerFactory(persistenceUnit, properties)); + EntityMgrCloser emc = new EntityMgrCloser(emfc.getFactory().createEntityManager()); + EntityTransCloser etc = new EntityTransCloser(emc.getManager().getTransaction())) { + + EntityManager em = emc.getManager(); + EntityTransaction et = etc.getTransation(); + + // Clean up the DB + em.createQuery("Delete from " + tableName).executeUpdate(); + + // commit transaction + et.commit(); + } + } + + /** + * Verifies that items appear within the log, in order. A given item may appear more than once. + * In addition, the log may contain extra items; those are ignored. + * + * @param textre regular expression used to extract an item from a line in the log. The first + * "capture" group of the regular expression is assumed to contain the extracted item + * @param items items that should be matched by the items extracted from the log, in order + * @throws IOException if an IO error occurs + * @throws AssertionError if the desired items were not all found + */ + protected void verifyItemsInLog(ExtractAppender app, String... items) throws IOException { + + Iterator<String> it = new ArrayList<>(Arrays.asList(items)).iterator(); + if (!it.hasNext()) { + return; + } + + String expected = it.next(); + String last = null; + + for (String extractedText : app.getExtracted()) { + if (extractedText.equals(expected)) { + if (!it.hasNext()) { + // matched all of the items + return; + } + + last = expected; + expected = it.next(); + + } else if (!extractedText.equals(last)) { + List<String> remaining = getRemaining(expected, it); + fail("missing items " + remaining + ", but was: " + extractedText); + } + } + + List<String> remaining = getRemaining(expected, it); + assertTrue("missing items " + remaining, remaining.isEmpty()); + } + + /** + * Gets the remaining items from an iterator. + * + * @param current the current item, to be included within the list + * @param it iterator from which to get the remaining items + * @return a list of the remaining items + */ + private LinkedList<String> getRemaining(String current, Iterator<String> it) { + LinkedList<String> remaining = new LinkedList<>(); + remaining.add(current); + + while (it.hasNext()) { + remaining.add(it.next()); + } + return remaining; + } + + /** + * Waits for a thread to stop. If the thread doesn't complete in the allotted time, then it + * interrupts it and waits again. + * + * @param auditor the thread for which to wait + * @return {@code true} if the thread stopped, {@code false} otherwise + */ + public boolean waitThread(MyIntegrityAudit auditor) { + if (auditor != null) { + try { + auditor.interrupt(); + + if (!auditor.joinAuditThread(WAIT_MS)) { + System.out.println("failed to stop audit thread"); + return false; + } + + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + + return true; + } + + /** + * Makes a new auditor. + * + * @param resourceName2 the name of the resource + * @param persistenceUnit2 the persistence unit + * @return a new auditor + * @throws Exception if an error occurs + */ + protected MyIntegrityAudit makeAuditor(String resourceName2, String persistenceUnit2) throws Exception { + return new MyIntegrityAudit(resourceName2, persistenceUnit2, makeProperties()); + } + + /** + * Watches for patterns in a logger by attaching a ExtractAppender to it. + * + * @param logger the logger to watch + * @param regex regular expression used to extract relevant text + * @return a new appender + */ + protected ExtractAppender watch(Logger logger, String regex) { + ExtractAppender app = new ExtractAppender(regex); + appenders.add(new LogApp(logger, app)); + + return app; + } + + /** + * Makes a new Property set that's a clone of {@link #properties}. + * + * @return a new Property set containing all of a copy of all of the {@link #properties} + */ + protected static Properties makeProperties() { + Properties props = new Properties(); + props.putAll(properties); + return props; + } + + /** + * Waits for data to become stale and then runs an audit on several auditors in parallel. + * + * @param auditors the auditors + * @throws InterruptedException if a thread is interrupted + */ + protected void waitStaleAndRun(MyIntegrityAudit... auditors) throws InterruptedException { + waitStale(); + runAudit(auditors); + } + + /** + * Runs an audit on several auditors in parallel. + * + * @param auditors the auditors + * @throws InterruptedException if a thread is interrupted + */ + protected void runAudit(MyIntegrityAudit... auditors) throws InterruptedException { + + // start an audit cycle on each auditor + List<CountDownLatch> latches = new ArrayList<>(auditors.length); + for (MyIntegrityAudit p : auditors) { + latches.add(p.startAudit()); + } + + // wait for each auditor to complete its cycle + for (CountDownLatch latch : latches) { + waitLatch(latch); + } + } + + /** + * Waits for a latch to reach zero. + * + * @param latch the latch to wait for + * @throws InterruptedException if the thread is interrupted + * @throws AssertionError if the latch did not reach zero in the allotted time + */ + protected void waitLatch(CountDownLatch latch) throws InterruptedException { + assertTrue(latch.await(WAIT_MS, TimeUnit.SECONDS)); + } + + /** + * Sleep a bit so that the currently designated pdp becomes stale. + * + * @throws InterruptedException if the thread is interrupted + */ + protected void waitStale() throws InterruptedException { + Thread.sleep(STALE_MS); + } + + /** + * Tracks which appender has been added to a logger. + */ + private static class LogApp { + private final Logger logger; + private final ExtractAppender appender; + + public LogApp(Logger logger, ExtractAppender appender) { + this.logger = logger; + this.appender = appender; + + logger.addAppender(appender); + + appender.start(); + } + + public void detach() { + logger.detachAppender(appender); + } + } + + /** + * Manages audits by inserting latches into a queue for the AuditThread to count. + */ + protected class MyIntegrityAudit extends IntegrityAudit { + + /** + * Queue from which the AuditThread will take latches. + */ + private BlockingQueue<CountDownLatch> queue = null; + + /** + * Constructs an auditor and starts the AuditThread. + * + * @param resourceName the resource name + * @param persistenceUnit the persistence unit + * @param properties the properties + * @throws Exception if an error occurs + */ + public MyIntegrityAudit(String resourceName, String persistenceUnit, Properties properties) throws Exception { + super(resourceName, persistenceUnit, properties); + + auditors.add(this); + + startAuditThread(); + } + + /** + * Interrupts the AuditThread. + */ + public void interrupt() { + super.stopAuditThread(); + } + + /** + * Triggers an audit by adding a latch to the queue. + * + * @return the latch that was added + * @throws InterruptedException if the thread is interrupted + */ + public CountDownLatch startAudit() throws InterruptedException { + CountDownLatch latch = new CountDownLatch(1); + queue.add(latch); + + return latch; + } + + /** + * Starts a new AuditThread. Creates a new latch queue and associates it with the thread. + */ + @Override + public final void startAuditThread() throws IntegrityAuditException { + if (queue != null) { + // queue up a bogus latch, in case a thread is still running + queue.add(new CountDownLatch(1) { + @Override + public void countDown() { + throw new RuntimeException("auditor has multiple threads"); + } + }); + } + + queue = new LinkedBlockingQueue<>(); + + if (super.startAuditThread(queue)) { + // wait for the thread to start + CountDownLatch latch = new CountDownLatch(1); + queue.add(latch); + + try { + waitLatch(latch); + + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new IntegrityAuditException(e); + } + } + } + + /** + * Stops the AuditThread and waits for it to stop. + * + * @throws AssertionError if the thread is still running + */ + @Override + public void stopAuditThread() { + super.stopAuditThread(); + + assertTrue(waitThread(this)); + } + } } diff --git a/integrity-audit/src/test/java/org/onap/policy/common/ia/jpa/IaTestEntity.java b/integrity-audit/src/test/java/org/onap/policy/common/ia/jpa/IaTestEntity.java index 43277a71..36b9ef66 100644 --- a/integrity-audit/src/test/java/org/onap/policy/common/ia/jpa/IaTestEntity.java +++ b/integrity-audit/src/test/java/org/onap/policy/common/ia/jpa/IaTestEntity.java @@ -37,119 +37,139 @@ import javax.persistence.Temporal; import javax.persistence.TemporalType; @Entity -@Table(name="IaTestEntity") -@NamedQueries({ - @NamedQuery(name=" IaTestEntity.findAll", query="SELECT e FROM IaTestEntity e "), - @NamedQuery(name="IaTestEntity.deleteAll", query="DELETE FROM IaTestEntity WHERE 1=1") -}) +@Table(name = "IaTestEntity") +@NamedQueries({@NamedQuery(name = " IaTestEntity.findAll", query = "SELECT e FROM IaTestEntity e "), + @NamedQuery(name = "IaTestEntity.deleteAll", query = "DELETE FROM IaTestEntity WHERE 1=1")}) public class IaTestEntity implements Serializable { - private static final long serialVersionUID = 1L; - - @Id - @GeneratedValue(strategy = GenerationType.AUTO) - @Column(name="ImTestId") - private long imTestId; - - @Column(name="created_by", nullable=false, length=255) - private String createdBy = "guest"; - - @Column(name="person", nullable=false, length=255) - private PersonSample person; - - @Temporal(TemporalType.TIMESTAMP) - @Column(name="created_date", updatable=false) - private Date createdDate; - - @Column(name="modified_by", nullable=false, length=255) - private String modifiedBy = "guest"; - - @Temporal(TemporalType.TIMESTAMP) - @Column(name="modified_date", nullable=false) - private Date modifiedDate; - - public IaTestEntity() { - } - - @PrePersist - public void prePersist() { - Date date = new Date(); - this.createdDate = date; - this.modifiedDate = date; - } - - @PreUpdate - public void preUpdate() { - this.modifiedDate = new Date(); - } - - /** - * @return the Id - */ - public long getImTestId() { - return imTestId; - } - - /** - * @return the createdBy - */ - public String getCreatedBy() { - return createdBy; - } - - /** - * @param createdBy the createdBy to set - */ - public void setCreatedBy(String createdBy) { - this.createdBy = createdBy; - } - - /** - * @return the modifiedBy - */ - public String getModifiedBy() { - return modifiedBy; - } - - /** - * @param modifiedBy the modifiedBy to set - */ - public void setModifiedBy(String modifiedBy) { - this.modifiedBy = modifiedBy; - } - - /** - * @return the modifiedDate - */ - public Date getModifiedDate() { - return modifiedDate; - } - - /** - * @param modifiedDate the modifiedDate to set - */ - public void setModifiedDate(Date modifiedDate) { - this.modifiedDate = modifiedDate; - } - - /** - * @return the createdDate - */ - public Date getCreatedDate() { - return createdDate; - } - - /** - * @param the person to set - */ - public void setPersonTest(PersonSample p) { - this.person = p; - } - - /** - * @return the person - */ - public PersonSample getPersonTest() { - return person; - } + private static final long serialVersionUID = 1L; + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + @Column(name = "ImTestId") + private long imTestId; + + @Column(name = "created_by", nullable = false, length = 255) + private String createdBy = "guest"; + + @Column(name = "person", nullable = false, length = 255) + private PersonSample person; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "created_date", updatable = false) + private Date createdDate; + + @Column(name = "modified_by", nullable = false, length = 255) + private String modifiedBy = "guest"; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "modified_date", nullable = false) + private Date modifiedDate; + + public IaTestEntity() {} + + /** + * PrePersist call back method. + */ + @PrePersist + public void prePersist() { + Date date = new Date(); + this.createdDate = date; + this.modifiedDate = date; + } + + @PreUpdate + public void preUpdate() { + this.modifiedDate = new Date(); + } + + /** + * The the Im test Id. + * + * @return the Id + */ + public long getImTestId() { + return imTestId; + } + + /** + * Get the createdBy. + * + * @return the createdBy + */ + public String getCreatedBy() { + return createdBy; + } + + /** + * Set the createdBy. + * + * @param createdBy the createdBy to set + */ + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + /** + * Get the modifiedBy. + * + * @return the modifiedBy + */ + public String getModifiedBy() { + return modifiedBy; + } + + /** + * Set the ModifiedBy. + * + * @param modifiedBy the modifiedBy to set + */ + public void setModifiedBy(String modifiedBy) { + this.modifiedBy = modifiedBy; + } + + /** + * Get the ModifiedDate. + * + * @return the modifiedDate + */ + public Date getModifiedDate() { + return modifiedDate; + } + + /** + * Set the ModifiedDate. + * + * @param modifiedDate the modifiedDate to set + */ + public void setModifiedDate(Date modifiedDate) { + this.modifiedDate = modifiedDate; + } + + /** + * Get the CreatedDate. + * + * @return the createdDate + */ + public Date getCreatedDate() { + return createdDate; + } + + /** + * Set the person. + * + * @param person the person to set + */ + public void setPersonTest(PersonSample person) { + this.person = person; + } + + /** + * Get the person. + * + * @return the person + */ + public PersonSample getPersonTest() { + return person; + } } diff --git a/integrity-audit/src/test/java/org/onap/policy/common/ia/jpa/PersonSample.java b/integrity-audit/src/test/java/org/onap/policy/common/ia/jpa/PersonSample.java index d7fcf330..47fa843b 100644 --- a/integrity-audit/src/test/java/org/onap/policy/common/ia/jpa/PersonSample.java +++ b/integrity-audit/src/test/java/org/onap/policy/common/ia/jpa/PersonSample.java @@ -23,42 +23,47 @@ package org.onap.policy.common.ia.jpa; import java.io.Serializable; public class PersonSample implements Serializable { - /** - * - */ - private static final long serialVersionUID = 1L; - private String firstName; - private String lastName; - private int age; - - public PersonSample(String first, String last, int age) { - this.firstName = first; - this.lastName = last; - this.age = age; - } - - public String getFirstName() { - return this.firstName; - } - - public void setFirstName(String name) { - this.firstName = name; - } - - public String getLasttName() { - return this.lastName; - } - - public void setLastName(String name) { - this.lastName = name; - } - - public int getAge() { - return this.age; - } - - public void setAge(int age) { - this.age = age; - } - + + private static final long serialVersionUID = 1L; + private String firstName; + private String lastName; + private int age; + + /** + * Create an instance. + * + * @param first first name + * @param last last name + * @param age age + */ + public PersonSample(String first, String last, int age) { + this.firstName = first; + this.lastName = last; + this.age = age; + } + + public String getFirstName() { + return this.firstName; + } + + public void setFirstName(String name) { + this.firstName = name; + } + + public String getLasttName() { + return this.lastName; + } + + public void setLastName(String name) { + this.lastName = name; + } + + public int getAge() { + return this.age; + } + + public void setAge(int age) { + this.age = age; + } + } |