com.disney.opa.service.queue.QueueService.java Source code

Java tutorial

Introduction

Here is the source code for com.disney.opa.service.queue.QueueService.java

Source

package com.disney.opa.service.queue;

import java.io.IOException;
import java.net.InetAddress;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Random;

import javax.annotation.Resource;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import com.disney.opa.dao.OpaQueueDao;
import com.disney.opa.dao.OptionDao;
import com.disney.opa.dao.ProductGroupDao;
import com.disney.opa.dao.SearchEngineDao;
import com.disney.opa.dom.bean.AgedUser;
import com.disney.opa.dom.operation.ComplianceOperationsLists;
import com.disney.opa.dom.preference.UserPreference;
import com.disney.opa.dom.product.BulkTask;
import com.disney.opa.dom.product.Product;
import com.disney.opa.dom.product.ProductState;
import com.disney.opa.dom.product.ProductSummary;
import com.disney.opa.dom.queue.jsonobject.ComplianceQueueJsonObject;
import com.disney.opa.dom.queue.jsonobject.ComplianceUserDeactivationQueueJsonObject;
import com.disney.opa.dom.queue.jsonobject.ComplianceUserWarningQueueJsonObject;
import com.disney.opa.dom.queue.jsonobject.ContractValidationQueueJsonObject;
import com.disney.opa.dom.queue.jsonobject.LicenseeQueueJsonObject;
import com.disney.opa.dom.queue.jsonobject.ProductQueueJsonObject;
import com.disney.opa.dom.user.User;
import com.disney.opa.entity.OPAProperty;
import com.disney.opa.exception.PADataAccessException;
import com.disney.opa.helper.user.UserPermission;
import com.disney.opa.json.response.ValidationResponse;
import com.disney.opa.mongoentity.OPAQueue;
import com.disney.opa.search.PASearchResultSet;
import com.disney.opa.search.SearchEngine;
import com.disney.opa.search.SearchItem;
import com.disney.opa.service.BulkTasksService;
import com.disney.opa.service.ContractService;
import com.disney.opa.service.PreferenceService;
import com.disney.opa.service.ProductService;
import com.disney.opa.service.UserService;
import com.disney.opa.service.UtilityService;
import com.disney.opa.service.WarningPolicyEnforcer;
import com.disney.opa.service.compliance.deactivation.DeactivationService;
import com.disney.opa.service.compliance.reactivation.ReactivationService;
import com.disney.opa.util.Constants;
import com.disney.opa.util.JDBCUtil;
import com.disney.opa.util.OpStatus;
import com.disney.opa.util.OperationUtil;
import com.disney.opa.util.PermissionUtil;
import com.disney.opa.util.ProductUtil;
import com.disney.opa.util.StringUtil;
import com.disney.opa.util.Utils;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Joiner;
import com.google.common.collect.Lists;

@Service
public class QueueService {

    static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("MM/dd/yyyy hh:mm:ss");

    private static String VALIDATE_CONTRACTS = "validateContract";
    private static String CHANGED_CONTRACTS = "loadProductsWhoseContractsAreUnknownOrChanged";
    private static String MIGRATION_PRODUCTS = "loadAllMigrationProducts";
    private static String DELETE_PRODUCTS = "DELETE";
    private static String REASSIGN_PRODUCTS = "REASSIGN";
    private static String CANCEL_PRODUCTS = "CANCEL";
    private static String APPROVE_PRODUCTS = "APPROVE";
    private static String SUSPEND_PRODUCTS = "SUSPEND";
    private static String UNCANCEL_PRODUCTS = "UNCANCEL";
    private static String UNAPPROVE_PRODUCTS = "UNAPPROVE";
    private static String APPROVE_EXTERNAL_PRODUCTS = "APPROVEEXTERNALLY";
    private static String UNSUSPEND_PRODUCTS = "UNSUSPEND";
    public static String CREATE_HARD_STOP_EXCEPTION = "CreateHardStopException";
    public static String REMOVE_HARD_STOP_EXCEPTION = "RemoveHardStopException";
    public static String CREATE_LICENSEE_HARD_STOP_EXCEPTION = "CreateLicenseeHardStopException";
    public static String REMOVE_LICENSEE_HARD_STOP_EXCEPTION = "RemoveLicenseeHardStopException";
    public static String OPA_COMPLIANCE_WARNING = "ENFORCE_WARNING_NOTIFICATION";
    public static String OPA_COMPLIANCE_EXPIRE = "ENFORCE_USER_EXPIRATION";
    public static String OPA_COMPLIANCE_DEACTIVATED_USER_AUDIT_ENTRY = "USER_DEACTIVATION_ENFORCED";
    public static String OPA_COMPLIANCE_REACTIVATED_USER_AUDIT_ENTRY = "USER_REACTIVATION_ENFORCED";
    public static String OPA_COMPLIANCE_AUDIT_ENTRY = "loadUsersWhoMeetTheCompliancePolicies";
    public static Integer USER_COMPLIANCE_EXPIRY_VALUE = 0;
    public static Integer USER_COMPLIANCE_SET_NOTIFICATION_FIELDS = 1;

    final Logger log = Logger.getLogger(this.getClass().getName());

    @Autowired
    private Utils utils;

    @Autowired
    private OpaQueueDao opaQueueDao;

    @Autowired
    private ContractService contractService;

    @Autowired
    private OperationUtil operationUtil;

    @Autowired
    private BulkTasksService bulkTasksService;

    @Autowired
    private UserService userService;

    @Autowired
    private WarningPolicyEnforcer warningPolicyEnforcer;

    @Resource
    private ProductGroupDao productGroupDao;

    @Resource
    private SearchEngineDao searchEngineDao;

    @Resource
    private PreferenceService preferencesService;

    @Resource
    private DeactivationService deactivationService;

    @Resource
    private ReactivationService reactivationService;

    @Resource
    private UtilityService utilityService;

    @Resource
    private OptionDao optionDao;

    @Resource(name = "productService")
    private ProductService productService;

    @Resource
    PermissionUtil permissionUtil;

    public void takeControlOfTenItems() throws Exception {
        List<OPAQueue> firstRecords = null;
        try {

            // delaying 150 -> 300 MS so as to cause randomization between the instances
            Random rand = new Random();
            int randomNum = rand.nextInt((300 - 150) + 1) + 150;
            Thread.sleep(randomNum);
            firstRecords = opaQueueDao.getFirstTenNonCompleteRecord();

            if (null != firstRecords) {
                //First we lay claim to the record (for use in multi server environments)
                for (OPAQueue q : firstRecords) {
                    q.setInUseBy(InetAddress.getLocalHost().getCanonicalHostName());
                    try {
                        opaQueueDao.updateRecord(q);
                    } catch (NullPointerException e) {
                        if (q.getId() == null) {
                            /* output the queue job so we can find the source of the issue. */
                            log.error("Error updating record OPAQueue has no ID; job: " + q.getJob());
                        }
                        throw e;
                    }
                }

            }

        } catch (Exception ex) {
            log.error("Exception: " + ex + " stacktrace: " + Utils.getStackTrace(ex));
            throw ex;
        } finally {

        }
    }

    public void reapDeadTasks() throws Exception {
        List<OPAQueue> firstRecords = null;
        try {
            firstRecords = opaQueueDao.reapDeadTasks();
            if (null != firstRecords) {
                //We'll let this retry up to three times
                for (OPAQueue q : firstRecords) {
                    Calendar LAST4HOUR = Calendar.getInstance();
                    LAST4HOUR.add(Calendar.HOUR, -4);

                    if (q.getCreationDate().before(LAST4HOUR.getTime())) {
                        //It's dead
                        q.setCompletionDate(new java.sql.Timestamp(Calendar.getInstance().getTime().getTime()));
                        q.setSuccess("0");
                    } else {
                        //Try again
                        q.setProcessing(null);
                        q.setInUseBy(null);
                    }
                    opaQueueDao.updateRecord(q);
                }

            }
        } catch (Exception ex) {
            log.error("Exception: " + ex + " stacktrace: " + Utils.getStackTrace(ex));
            throw ex;
        } finally {

        }
    }

    @Async
    public void processJob(List<OPAQueue> queueItems) throws Exception {
        try {
            Map<String, List<OPAQueue>> jobs = new HashMap<String, List<OPAQueue>>();
            //Build list of jobs
            for (OPAQueue queueItem : queueItems) {
                if (jobs.get(queueItem.getJob()) == null) {
                    List<OPAQueue> qs = new ArrayList<OPAQueue>();
                    qs.add(queueItem);
                    jobs.put(queueItem.getJob(), qs);
                } else {
                    List<OPAQueue> qs = jobs.get(queueItem.getJob());
                    qs.add(queueItem);
                    jobs.put(queueItem.getJob(), qs);
                }
            }
            for (String job : jobs.keySet()) {
                if (job.equalsIgnoreCase(VALIDATE_CONTRACTS)) {
                    processContractItem(jobs.get(job));
                } else if (job.equalsIgnoreCase(CHANGED_CONTRACTS)) {
                    processProductsWhoseContractsAreUnknownOrChanged(jobs.get(job));
                } else if (job.equalsIgnoreCase(MIGRATION_PRODUCTS)) {
                    processAllMigrationProducts(jobs.get(job));
                } else if (job.equalsIgnoreCase(DELETE_PRODUCTS)) {
                    processAllDeleteProducts(jobs.get(job));
                } else if (job.equalsIgnoreCase(REASSIGN_PRODUCTS)) {
                    processAllReassignProducts(jobs.get(job));
                } else if (job.equalsIgnoreCase(CANCEL_PRODUCTS)) {
                    processAllCancelProducts(jobs.get(job));
                } else if (job.equalsIgnoreCase(APPROVE_PRODUCTS)) {
                    processAllApproveProducts(jobs.get(job));
                } else if (job.equalsIgnoreCase(SUSPEND_PRODUCTS)) {
                    processAllSuspendProducts(jobs.get(job));
                } else if (job.equalsIgnoreCase(UNCANCEL_PRODUCTS)) {
                    processAllUnCancelProducts(jobs.get(job));
                } else if (job.equalsIgnoreCase(UNAPPROVE_PRODUCTS)) {
                    processAllUnApproveProducts(jobs.get(job));
                } else if (job.equalsIgnoreCase(APPROVE_EXTERNAL_PRODUCTS)) {
                    processAllApproveExternallyProducts(jobs.get(job));
                } else if (job.equalsIgnoreCase(UNSUSPEND_PRODUCTS)) {
                    processAllUnSuspendProducts(jobs.get(job));
                } else if (job.equalsIgnoreCase(CREATE_HARD_STOP_EXCEPTION)) {
                    processAllCreateHardStopProducts(jobs.get(job));
                } else if (job.equalsIgnoreCase(REMOVE_HARD_STOP_EXCEPTION)) {
                    processAllRemoveHardStopProducts(jobs.get(job));
                } else if (job.equalsIgnoreCase(CREATE_LICENSEE_HARD_STOP_EXCEPTION)) {
                    processAllCreateHardStopLicensees(jobs.get(job));
                } else if (job.equalsIgnoreCase(REMOVE_LICENSEE_HARD_STOP_EXCEPTION)) {
                    processAllRemoveHardStopLicensees(jobs.get(job));
                } else if (job.equalsIgnoreCase(OPA_COMPLIANCE_WARNING)) {
                    processAllWarningRecords(jobs.get(job));
                } else if (job.equalsIgnoreCase(OPA_COMPLIANCE_EXPIRE)) {
                    processAllExpiryRecords(jobs.get(job));
                } else if (job.equalsIgnoreCase(OPA_COMPLIANCE_AUDIT_ENTRY)) {
                    processComplianceAuditEntry(jobs.get(job));
                }
            }

        } catch (Exception ex) {
            log.error("Exception: " + ex + " stacktrace: " + Utils.getStackTrace(ex));
            throw ex;
        } finally {

        }
    }

    //there should only be one audit record per day
    //this record is the list of users that meet the Compliance policies
    //DEV NOTE: auditRecord is a List<OPAQueue> with one member
    public <T extends ComplianceQueueJsonObject> List<OPAQueue> processComplianceAuditEntry(
            List<OPAQueue> auditRecord) throws Exception {
        ObjectMapper mapper = new ObjectMapper();

        /* TODO warningPolicyEnforcer.getDeltaList is no longer used so is this code useful anymore? */
        OPAProperty prop = utilityService.getOPAProperty("OPA_COMPLIANCE_AGING_DELTAS");
        String deltaValues = prop.getValue();
        List<Integer> deltaList = StringUtil.getIntegerList(deltaValues, ",");
        warningPolicyEnforcer.setDeltaList(deltaList);

        if (auditRecord != null && !auditRecord.isEmpty()) {
            for (OPAQueue q : auditRecord) {
                /* We want the try-catch block within the List<OPAQueue> loop 
                 * because we want other queue records (jobs) to process.  This
                 * is less likely with these records because they should be 
                 * created once daily (except for testing). 
                 */
                try {

                    //This is the big auditEntry list of users that meet the compliance policy for user aging
                    List<ComplianceUserWarningQueueJsonObject> complianceQueueJsonObjectList = mapper.readValue(
                            q.getJsonData(), new TypeReference<List<ComplianceUserWarningQueueJsonObject>>() {
                            });

                    //create a queue entry for each user in the list above
                    //i.e. create N-warningEntries/expiryEntries out of 1 auditEntry
                    for (ComplianceUserWarningQueueJsonObject queueJsonObject : complianceQueueJsonObjectList) {

                        /* Use the User object to determine if user has been notified before.
                         * 1. If Notification Flag is null (they have not been notified, so notify them)
                         * 2. If new flag (from OPAQueue job record) is less than current flag (notify them again; or expire them)
                         * Notes:
                         * a. We NEVER purge the OpaQueue, so we MUST use the User record to determine if user has been notified
                         *    - E.g. System notifies you; you log back in; 60 days later - when you have not logged in again -
                         *           you should get another 60 day notification; and so on and so on.
                         * b. This will work for future use if Business decides to notify user after expiration (negative 
                         *    numbers for notif. flag)
                         * c. User object falls under our 2-minute cache; so we should not have stale data issues.
                         */
                        User user = userService.get(queueJsonObject.getUserId(), JDBCUtil.IGNORED);
                        Integer currentNotifFlag = user.getNotificationFlag();

                        // newNotifFlag should never be null
                        Integer newNotifFlag = queueJsonObject.getNotificationFlag();
                        boolean createJob = false;
                        if (currentNotifFlag == null) {
                            log.debug("Current Notification Flag is NULL; so we notify the user.");
                            // user has not been recently notified
                            createJob = true;
                        } else if (newNotifFlag < currentNotifFlag) {
                            log.debug(
                                    "New Notification Flag is less than Current Notification Flag; so we notify the user (or expire them).");
                            /* User has been notified and we do not want to notify
                             * (or expire) them immediately after - that is why we
                             * use < and not not <=.
                             */
                            createJob = true;
                        }

                        // TODO Remove this once confirmed
                        log.info(String.format("User: %s; currentNotifFlag: %s; newNotifFlag: %s; createJob: %s;",
                                queueJsonObject.getUserId(), currentNotifFlag, newNotifFlag, createJob));

                        OPAQueue newQ = new OPAQueue();
                        newQ.setCreationDate(new java.sql.Timestamp(Calendar.getInstance().getTime().getTime()));
                        newQ.setCreatedBy(Constants.SYSTEM_USER);

                        //create an EXPIRY job for this user
                        if (queueJsonObject.getNotificationFlag() == USER_COMPLIANCE_EXPIRY_VALUE) {
                            //ComplianceUserDeactivationQueueJsonObject deactivationJsonObject = new ComplianceUserDeactivationQueueJsonObject();
                            //deactivationJsonObject.setUserId(queueJsonObject.getUserId());
                            //deactivationJsonObject.setNotificationFlag(queueJsonObject.getNotificationFlag());

                            //newQ.setJsonData(mapper.writeValueAsString(deactivationJsonObject));
                            newQ.setJob(OPA_COMPLIANCE_EXPIRE);

                        } else if (queueJsonObject.getNotificationFlag() > USER_COMPLIANCE_EXPIRY_VALUE) { //create a NOTIFICATION job for this user

                            //newQ.setJsonData(mapper.writeValueAsString(queueJsonObject));
                            newQ.setJob(OPA_COMPLIANCE_WARNING);

                        } else { //some undesirable value...like null
                            log.error("user: " + queueJsonObject.getUserId()
                                    + " has a notificationFlag with a value of: "
                                    + queueJsonObject.getNotificationFlag());
                            log.error("this value is undesirable and is not being considered.");
                        }

                        if (createJob) {
                            //set the parent for this record before we create the new record
                            //this is done regardless of the type of queue record we are creating
                            newQ.setParentId(q.getId());
                            newQ.setJsonData(mapper.writeValueAsString(queueJsonObject));

                            Long newId = opaQueueDao.createRecord(newQ);
                            log.info("Created New Queue Record (ID: " + String.valueOf(newId) + ") "
                                    + String.valueOf(newQ));
                        } else {
                            log.info("New Queue Record Not Created: " + String.valueOf(newQ));
                        }
                    }

                    // set successful completion on the audit record
                    q.setCompletionDate(new java.sql.Timestamp(Calendar.getInstance().getTime().getTime()));
                    q.setSuccess("1");

                    opaQueueDao.updateRecord(q);

                } catch (Exception e) {
                    q.setCompletionDate(new java.sql.Timestamp(Calendar.getInstance().getTime().getTime()));
                    q.setSuccess("0");
                    q.setErrorMsg(e.getMessage());
                    opaQueueDao.updateRecord(q);
                    log.error("Exception in processComplianceAuditEntry", e);
                }

            } // END LOOP auditRecord
        } // END IF auditRecord not empty

        return auditRecord;
    }

    private boolean isJsonDataEmpty(String testForEmpty) {
        boolean isJsonDataEmpty = true;

        if (testForEmpty.replace("[", "").replace("]", "").length() > 0) {
            isJsonDataEmpty = false;
        }

        return isJsonDataEmpty;
    }

    //every entry in expirationEntries should have a notificationFlag of 0
    //the user has already received the requisite number of notifications
    //and now we go about the business of handling their products and tasks as applicable
    //and if that is successfully, then we flip the user's active flag off
    //NOTE: we may want to do a last and final check to see if the user has logged in?????
    public void processAllExpiryRecords(List<OPAQueue> expirationEntries) throws PADataAccessException {

        ObjectMapper mapper = new ObjectMapper();
        ComplianceUserDeactivationQueueJsonObject userToDeactivate = null;
        PASearchResultSet[] userProductsSet = null;
        PASearchResultSet rs = null;
        ComplianceOperationsLists complianceOperationsLists = null;
        int userId = 0;

        for (OPAQueue q : expirationEntries) {

            /* We want the try-catch block within the List<OPAQueue> loop because
             * we want other queue records (jobs) to process, especially 
             * because expiry records are created by 
             * QueueService.processComplianceAuditEntry.
             */
            try {

                //TMA: if for some reason we pick up a record with empty jsonData, we don't want 
                //a JsonMappingException because we can't deserialize []
                if (!isJsonDataEmpty(q.getJsonData())) {
                    userToDeactivate = mapper.readValue(q.getJsonData(),
                            ComplianceUserDeactivationQueueJsonObject.class);

                    userId = userToDeactivate.getUserId();
                    userProductsSet = searchForProductsUserIsAssociatedWith(userId);
                    rs = userProductsSet[0];
                    /* This cannot be a Singleton (it was) because the list is unique per OPAQueue (q variable) instance. */
                    complianceOperationsLists = new ComplianceOperationsLists();

                    //we need to make sure the user is associated with products
                    if (rs != null) {
                        for (SearchItem si : rs.getSearchItems()) {
                            if (si != null) {
                                /* There has to be a better way to go from Product Summary to UserPermission!
                                 * Having to get Product (AND State) to get UserPermission */
                                ProductSummary psum = si.getProductSummary();
                                /* We are mostly using product ID, so populateAvailableOptions can be false */
                                Product product = productService.get(psum.getProductID(),
                                        Constants.LANGUAGE_ENGLISH, false, Constants.PRODUCT_ACTIVE);
                                if (product != null) {
                                    ProductState state = productService.getProductState(psum.getProductID());
                                    UserPermission up = new UserPermission(userId, product, state, permissionUtil);

                                    /* We need to pass userToDeactivate so that
                                     * productIDs are added to the payload for the
                                     * job.  We need to pass complianceOperationsLists
                                     * in order to pass applicable Products to 
                                     * be deactivated.
                                     */
                                    generateProductDeactivationTaxonomies(q, userId, product, up, userToDeactivate,
                                            complianceOperationsLists);
                                } //if (product != null)

                            } //if (si != null)
                        } //for si : rs.getSearchItems()

                        /* Perform De-activation of User and Products! */
                        userToDeactivate
                                .setErrorMessages(deactivationService.deactivate(q, complianceOperationsLists));

                        // Add product lists and user data to response payload.
                        q.setJsonData(mapper.writeValueAsString(userToDeactivate));

                        //only set the success flag if all the errorMessage maps are empty
                        //otherwise, we failed somewhere and the user can't be deactivated
                        if (deactivationService.isProductDeactivationSuccess() == true) {
                            q.setSuccess("1");

                            //try and deactivate the user
                            if (!deactivationService.deactivateUser(userToDeactivate)) { //we failed to flip the user's active switch
                                q.setSuccess("0");
                                q.setErrorMsg(
                                        "While this user's products/tasks may have been deactivated, the user account is still active.");
                            }
                        } else {
                            q.setSuccess("0");
                            q.setErrorMsg(
                                    "An error happened while trying to deactivate this user's products/tasks.");

                            /* Does userToDeactivate.setErrorMessages properly
                             * display the errors in details.
                             */
                        }

                        q.setCreatedBy(-1);
                        q.setCreationDate(new Date());
                        opaQueueDao.updateRecord(q);
                        log.info(q.getJob() + " succeeded " + q.getJsonData());
                    } else { //if (rs !=null)
                        //user has no products....we still need to flip their active flag
                        //only set the success flag if all the errorMessage maps are empty
                        //otherwise, we failed somewhere and the user can't be deactivated
                        q.setSuccess("1");
                        if (!deactivationService.deactivateUser(userToDeactivate)) {
                            q.setSuccess("0");
                            q.setErrorMsg(
                                    "While this user's products/tasks may have been deactivated, the user account is still active.");
                        }
                        q.setCreatedBy(-1);
                        q.setCreationDate(new Date());
                        opaQueueDao.updateRecord(q);
                        log.info(q.getJob() + " succeeded " + q.getJsonData());

                    }
                } else {//if jsonData is empty
                    throw new PADataAccessException("The jsonData is null");
                }
            } catch (JsonProcessingException e) {
                q.setCompletionDate(new java.sql.Timestamp(Calendar.getInstance().getTime().getTime()));
                q.setSuccess("0");
                q.setErrorMsg(e.getMessage());
                opaQueueDao.updateRecord(q);
                log.error("JsonProcessingException in processAllExpiryRecords", e);
            } catch (IOException e) {
                q.setCompletionDate(new java.sql.Timestamp(Calendar.getInstance().getTime().getTime()));
                q.setSuccess("0");
                q.setErrorMsg(e.getMessage());
                opaQueueDao.updateRecord(q);
                log.error("IOException in processAllExpiryRecords", e);
            } catch (Exception e) {
                q.setCompletionDate(new java.sql.Timestamp(Calendar.getInstance().getTime().getTime()));
                q.setSuccess("0");
                q.setErrorMsg(e.getMessage());
                opaQueueDao.updateRecord(q);
                log.error("Unknown Exception in processAllExpiryRecords", e);
            }

        } // END MAIN OUTER FOR LOOP 

    }

    private void generateProductDeactivationTaxonomies(OPAQueue queueMember, int userId, Product product,
            UserPermission userPermission, ComplianceUserDeactivationQueueJsonObject deactivationObject,
            ComplianceOperationsLists complianceOperationsLists) {

        try {
            int productID = product.getID();

            /* See processAllExpiryRecords. */
            if (complianceOperationsLists == null) {
                complianceOperationsLists = new ComplianceOperationsLists();
            }
            complianceOperationsLists.setUserId(userId);

            /* keep a record of all products regardless of what the user's role
             * is on the product
             */
            deactivationObject.getUserProductList().add(productID);

            // if isReviewer, add this product to the tasksToCancelList
            if (userPermission.isActAsReviewer()) {
                deactivationObject.getTasksToCancel().add(productID);
                complianceOperationsLists.getTasksToCancel().add(product);
            }

            /* if user is associate, then deactivate the product.  For 
             * publishing products, the product goes to a PUBHOLDING account
             * (a Reassign).  For merchandising products, the product goes to 
             * the licensee (a Resubmit).
             * It is technically possible that the same user is a reviewer and
             * an associate on the product (although application is supposed to
             * not allow this), so it is fine to separate these conditionals.
             * 
             * As for the else-if....
             * By inference if user is not Reviewer and not Associate and is 
             * assigned they are the Licensee (for Standard, Range and Packaging
             * products).  You can also be Assigned user as the Lead, but we
             * only assign leads for FNS (FHB) components.
             * In #processAllExpiryRecords, we search for only Standard, Range 
             * and Packaging, but it is *possible* searches will return more 
             * product types.  Therefore, it should work to suspend products
             * if user is assigned because products with Licensees simply get 
             * suspended.  Also, we should not have FNS components in this list
             * so the likelihood of someone being a Lead is small.
             */
            if (userPermission.isActAsAssociate()) {
                if (ProductUtil.isDPW(product.getProductTemplateID())) {
                    deactivationObject.getProductsToReassign().add(productID);
                    complianceOperationsLists.getProductsToReassign().add(product);
                } else {
                    deactivationObject.getProductsToResubmit().add(productID);
                    complianceOperationsLists.getProductsToResubmit().add(product);
                }
            } else if (userPermission.isActAsLicensee()) {
                deactivationObject.getProductsToSuspend().add(productID);
                complianceOperationsLists.getProductsToSuspend().add(product);
            }

        } catch (Exception e) {
            log.error("Caught exception in generateProductDeactivationTaxonomies", e);
        }

    }

    public void reactivateUser(Long id) {

        OPAQueue reactivationRecord = opaQueueDao.fetchRecordByID(id);

        reactivationService.reactivate(reactivationRecord);

        reactivationRecord.setCompletionDate(new java.sql.Timestamp(Calendar.getInstance().getTime().getTime()));
        reactivationRecord.setSuccess("1");
        opaQueueDao.updateRecord(reactivationRecord);
    }

    public void processAllWarningRecords(List<OPAQueue> opaQueueWarningEntries) {

        //TMA: 11/03/2015 --> we were pulling the latest data from the database
        //but now we are doing the following:
        //1. loop through the warning entries from the queue
        //2. for each entry, get the User object (using the userId) and determine if
        //   user.lastLoginDate().equals(today)
        //3. if true, then skip the user (because they are now in compliance)
        //4. if false, enforce the warning policy on this user
        //5. set the success flag, completionDate and update the queue record
        //List<ComplianceQueueJsonObject> candidateResultList = retrieveAgingCandidates(OPA_COMPLIANCE_WARNING);
        //don't enforce the policy if there are no users that meet the policy to be enforced
        //if (!candidateResultList.isEmpty()) {
        //   warningPolicyEnforcer.enforcePolicy(candidateResultList);
        //}

        //don't enforce the policy if there are no users that meet the policy to be enforced
        if (!opaQueueWarningEntries.isEmpty()) {
            for (OPAQueue q : opaQueueWarningEntries) {
                ObjectMapper mapper = new ObjectMapper();
                ComplianceUserWarningQueueJsonObject warningJson;

                /* We want the try-catch block within the List<OPAQueue> loop because
                 * we want other queue records (jobs) to process, especially 
                 * because warning records are created by 
                 * QueueService.processComplianceAuditEntry.
                 */
                try {
                    warningJson = mapper.readValue(q.getJsonData(), ComplianceUserWarningQueueJsonObject.class);

                    User user = userService.get(warningJson.getUserId(), 1);
                    Locale locale = userService.getLocale(user);

                    //we have to do this check here because we are pulling records from the queue and
                    //not re-running the spComplianceFindAgingCandidates
                    //so the user *may* have logged in since the last time we ran the
                    //scan therefore putting the user in compliance with Disney policies.
                    if ((user.getLastLoginDate() == null) //if lastLoginDate is null, the user has never logged in
                            || (!user.getLastLoginDate()
                                    .equals(new java.sql.Timestamp(Calendar.getInstance().getTime().getTime())))) { //the user hasn't logged in today such that they are in compliance now...our data is clean
                        //enforce the warning policy on this user
                        warningPolicyEnforcer.enforcePolicy(locale, warningJson);
                    }

                    //} else if (!user.getLastLoginDate().equals(new Date())) {
                    //   warningPolicyEnforcer.enforcePolicy(warningJson);
                    //}

                    //the OPA pattern of behavior when doing queue manipulations...
                    //sent the completionDate, setSuccess...update the record
                    q.setCompletionDate(new java.sql.Timestamp(Calendar.getInstance().getTime().getTime()));
                    q.setSuccess("1");
                    opaQueueDao.updateRecord(q);
                    log.info(q.getJob() + " succeeded " + q.getJsonData());

                } catch (JsonParseException e) {
                    q.setCompletionDate(new java.sql.Timestamp(Calendar.getInstance().getTime().getTime()));
                    q.setSuccess("0");
                    q.setErrorMsg(e.getMessage());
                    opaQueueDao.updateRecord(q);
                    log.error("JsonParseException in processAllWarningRecords", e);
                } catch (JsonMappingException e) {
                    q.setCompletionDate(new java.sql.Timestamp(Calendar.getInstance().getTime().getTime()));
                    q.setSuccess("0");
                    q.setErrorMsg(e.getMessage());
                    opaQueueDao.updateRecord(q);
                    log.error("JsonMappingException in processAllWarningRecords", e);
                } catch (IOException e) {
                    q.setCompletionDate(new java.sql.Timestamp(Calendar.getInstance().getTime().getTime()));
                    q.setSuccess("0");
                    q.setErrorMsg(e.getMessage());
                    opaQueueDao.updateRecord(q);
                    log.error("IOException in processAllWarningRecords", e);
                } catch (Exception e) {
                    q.setCompletionDate(new java.sql.Timestamp(Calendar.getInstance().getTime().getTime()));
                    q.setSuccess("0");
                    q.setErrorMsg(e.getMessage());
                    opaQueueDao.updateRecord(q);
                    log.error("Unknown Exception in processAllWarningRecords", e);
                }
            }
        }
    }

    public ArrayList<ComplianceQueueJsonObject> retrieveAgingCandidates(String candidacyType) {

        //get the list of users from the RDBMS who meet the Compliance Policies
        //we pull this info from the database every time warnings/expiries are processed
        //(as opposed to pulling the entries off of the queue)
        //because the user may have logged in from the last time the record
        //was put on the queue.
        Collection<AgedUser> candidateResultList = userService.findAgingCandidates();

        //we only want the list to have either warning or expiry users...not both
        ArrayList<ComplianceQueueJsonObject> warningList = new ArrayList<ComplianceQueueJsonObject>();
        ArrayList<ComplianceQueueJsonObject> expiryList = new ArrayList<ComplianceQueueJsonObject>();

        ObjectMapper jsonData = new ObjectMapper();

        try {
            OPAProperty prop = utilityService.getOPAProperty("OPA_COMPLIANCE_AGING_DELTAS");
            String deltaValues = prop.getValue();
            List<Integer> deltaList = StringUtil.getIntegerList(deltaValues, ",");

            warningPolicyEnforcer.setDeltaList(deltaList);

            log.info("from the database: " + jsonData.writeValueAsString(candidateResultList));

            //This is the big auditEntry list of users that meet the compliance policy for user aging
            List<ComplianceQueueJsonObject> ComplianceQueueJsonObjectList;

            ComplianceQueueJsonObjectList = jsonData.readValue(jsonData.writeValueAsString(candidateResultList),
                    new TypeReference<List<ComplianceQueueJsonObject>>() {
                    });

            //create a queue entry for each user in the list above
            //i.e. create N-warningEntries/expiryEntries out of 1 auditEntry
            for (ComplianceQueueJsonObject dbEntry : ComplianceQueueJsonObjectList) {

                //if the value of the notificationFlag == 0, we expire the user
                if (dbEntry.getNotificationFlag() == USER_COMPLIANCE_EXPIRY_VALUE) {
                    expiryList.add(dbEntry);
                } else if (dbEntry.getNotificationFlag() > USER_COMPLIANCE_EXPIRY_VALUE) { //send the user a warning.
                    warningList.add(dbEntry);
                } else { //some undesirable value...like null
                    log.error("user: " + dbEntry.getUserId() + " has a notificationFlag with a value of: "
                            + dbEntry.getNotificationFlag());
                    log.error("this value is undesirable and is not being considered.");
                }

            }

        } catch (JsonProcessingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (PADataAccessException e) {
            e.printStackTrace();
        }

        if (candidacyType.equals(OPA_COMPLIANCE_WARNING)) {
            return warningList;
        } else if (candidacyType.equals(OPA_COMPLIANCE_EXPIRE)) {
            return expiryList;
        }

        return null;
    }

    //NOTE: TMA 9/28/2015. -- On Friday, 9/25/2015, I stole this from somewhere...but I didn't make a note of where I stole this from
    private PASearchResultSet[] searchForProductsUserIsAssociatedWith(int userId) {
        PASearchResultSet[] resultSets = null;
        int searchUserId = 1;

        try {
            UserPreference preference = preferencesService.getUserPreferences(searchUserId);
            int languageId = (preference == null) ? 1 : preference.getPreferredLanguageID();
            int searchTypeId = SearchEngine.ACTIVE;
            int returnStatusSummary = SearchEngine.PRODUCT_SUMMARY;
            //int returnStatusSummary = SearchEngine.COMPLETED;
            int pageNumber = 1;
            int searchPageSize = 99999999; // ALL products

            int[] userIds = { userId };
            int[] companyId = null;
            int[] productTypeIDs = new int[] { Product.TYPE_STANDARD, Product.TYPE_PACKAGE,
                    Product.TYPE_RANGE_PARENT, Product.TYPE_COMPONENT, Product.TYPE_PI_COMPONENT };
            //TODO: need to remember to drop LINE_LISTS from this set..but how do you do this?
            int[] productIds = null;
            int[] phaseIds = null;
            String keywords = null;
            int[] collectionIds = null;

            resultSets = searchEngineDao.search(searchTypeId, productIds, userIds, languageId, companyId,
                    returnStatusSummary, phaseIds, productTypeIDs, //change this (TMA.....toooooo?  This is a comment from the existing code.  I don't know what to change this to.)
                    keywords, null, //Query null : b'se of using data table pagination not needed 
                    pageNumber, searchPageSize, null, //sort
                    searchUserId, collectionIds, false);// isMarvelId = false

        } catch (Exception ex) {
            System.out.println(ex);
        }

        return resultSets;

    }

    public List<OPAQueue> readQueueItems(String day, String productId, String operationType, int user, String jobId)
            throws Exception {

        List<OPAQueue> opaQueues = null;
        try {

            if (user != 0 && day != null) {

                String startDay = day + " 00:00:01";
                String endDay = day + " 23:59:59";

                Date createDate = DATE_FORMAT.parse(startDay);
                Date endDate = DATE_FORMAT.parse(endDay);

                if (-99 == user) {

                    opaQueues = opaQueueDao.fetchRecordsByDay(createDate, endDate);

                } else {

                    opaQueues = opaQueueDao.fetchRecordsByUserandDay(user, createDate, endDate);

                }

            }

            if (jobId != null) {
                log.debug("attempting to call : fetchRecordsByRefId(" + Long.parseLong(jobId) + ");");
                opaQueues = opaQueueDao.fetchRecordsByRefId(Long.parseLong(jobId));
            }

        } catch (ParseException pe) {
            log.error("Error parsing readQueueItems", pe);
        }

        return opaQueues;

    }

    public List<Integer> userByDay(String day) throws Exception {
        log.debug("day : " + day);
        List<Integer> userList = null;
        try {

            if (day != null) {

                String startDay = day + " 00:00:01";
                String endDay = day + " 23:59:59";
                log.debug("startDay : " + startDay);
                log.debug("endDay : " + endDay);
                Date createDate = DATE_FORMAT.parse(startDay);
                Date endDayDate = DATE_FORMAT.parse(endDay);
                log.debug("createDate : " + createDate.getTime());
                log.debug("endDate : " + endDayDate.getTime());

                log.debug("getUsersByDay");
                userList = opaQueueDao.getUsersByDay(createDate, endDayDate);
                log.debug("added one more");

            }

        } catch (ParseException pe) {
            log.error("Error parsing readQueueItems", pe);
        }

        return userList;

    }

    public Long create(String jobName, String jsonData, int user) throws Exception {

        Long id = null;

        try {

            OPAQueue queueRecord = new OPAQueue();
            queueRecord.setCreationDate(new java.sql.Timestamp(Calendar.getInstance().getTime().getTime()));
            queueRecord.setJob(jobName);
            queueRecord.setCreatedBy(user);
            queueRecord.setJsonData(jsonData);

            id = opaQueueDao.createRecord(queueRecord);

        } catch (Exception pe) {
            log.error("Error in record saving in the Queue", pe);
        }

        return id;

    }

    public List<OPAQueue> grabNonProcessingTasks() throws Exception {
        List<OPAQueue> firstRecords = null;
        try {
            String myHost = InetAddress.getLocalHost().getCanonicalHostName();
            firstRecords = opaQueueDao.getFirstTenNonCompleteRecordOwnedByMyHostNotProcessing(myHost);

            if (null != firstRecords) {
                //First we lay claim to the record (for use in multi server environments)
                for (OPAQueue q : firstRecords) {
                    q.setProcessing("1");
                    opaQueueDao.updateRecord(q);
                }
            }
            return firstRecords;
        } catch (Exception ex) {
            //            utils.LogExceptionAndSendEmail("ReaderScheduler", ex);
            throw ex;
        } finally {

        }
    }

    public List<OPAQueue> processContractItem(List<OPAQueue> firstRecords) throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        try {
            for (OPAQueue q : firstRecords) {
                ContractValidationQueueJsonObject cvo = mapper.readValue(q.getJsonData(),
                        ContractValidationQueueJsonObject.class);
                ArrayList<Integer> productsWithErrors = new ArrayList<Integer>();
                for (int productId : cvo.getProductIds()) {
                    ValidationResponse cr = null;
                    try {
                        cr = contractService.validateContractForProductIdAndSave(productId);
                    } catch (Exception e) {
                        // If we throw an error on a given item, continue executing
                        utils.LogExceptionAndSendEmail(
                                "validateContractForProductIdAndSave for input: " + productId, e);
                    }
                    if (null == cr) {
                        productsWithErrors.add(productId);
                    }
                }
                if (productsWithErrors.size() > 0) {
                    q.setSuccess("0");
                    q.setErrorMsg("Error validating contract via automated job for productIDs = "
                            + Joiner.on(",").join(productsWithErrors));
                } else {
                    q.setSuccess("1");
                }
                q.setCompletionDate(new java.sql.Timestamp(Calendar.getInstance().getTime().getTime()));
                opaQueueDao.updateRecord(q);
            }

        } catch (Exception ex) {
            //            utils.LogExceptionAndSendEmail("ReaderScheduler", ex);
            throw ex;
        } finally {

        }
        return firstRecords;
    }

    public List<OPAQueue> processProductsWhoseContractsAreUnknownOrChanged(List<OPAQueue> firstRecords)
            throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        try {
            for (OPAQueue q : firstRecords) {
                List<Integer> products = contractService.getProductsWhoseLicenseeChanged();
                log.debug("# of products to validate :" + products.size());
                List<List<Integer>> productsOf25 = Lists.partition(products, 25);
                for (List<Integer> prod25 : productsOf25) {
                    OPAQueue queueRecord = new OPAQueue();
                    queueRecord.setCreationDate(new java.sql.Timestamp(Calendar.getInstance().getTime().getTime()));
                    queueRecord.setJob("validateContract");
                    queueRecord.setCreatedBy(-1);
                    ContractValidationQueueJsonObject cvo = new ContractValidationQueueJsonObject();
                    cvo.setProductIds(prod25);
                    queueRecord.setJsonData(mapper.writeValueAsString(cvo));
                    opaQueueDao.createRecord(queueRecord);
                }

                q.setCompletionDate(new java.sql.Timestamp(Calendar.getInstance().getTime().getTime()));
                q.setSuccess("1");
                opaQueueDao.updateRecord(q);
            }

        } catch (Exception ex) {
            //            utils.LogExceptionAndSendEmail("ReaderScheduler", ex);
            throw ex;
        } finally {

        }
        return firstRecords;
    }

    public List<OPAQueue> processAllMigrationProducts(List<OPAQueue> firstRecords) throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        try {
            for (OPAQueue q : firstRecords) {
                List<Integer> products = contractService.getAllMigrationProducts();
                List<List<Integer>> productsOf25 = Lists.partition(products, 25);
                for (List<Integer> prod25 : productsOf25) {
                    OPAQueue queueRecord = new OPAQueue();
                    queueRecord.setCreationDate(new java.sql.Timestamp(Calendar.getInstance().getTime().getTime()));
                    queueRecord.setJob("validateContract");
                    queueRecord.setCreatedBy(-1);
                    ContractValidationQueueJsonObject cvo = new ContractValidationQueueJsonObject();
                    cvo.setProductIds(prod25);
                    queueRecord.setJsonData(mapper.writeValueAsString(cvo));
                    opaQueueDao.createRecord(queueRecord);
                }
                q.setCompletionDate(new java.sql.Timestamp(Calendar.getInstance().getTime().getTime()));
                q.setSuccess("1");
                opaQueueDao.updateRecord(q);
            }

        } catch (Exception ex) {
            //            utils.LogExceptionAndSendEmail("ReaderScheduler", ex);
            throw ex;
        } finally {

        }
        return firstRecords;
    }

    public List<OPAQueue> processAllDeleteProducts(List<OPAQueue> firstRecords) throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        int adminUserId = 0, currentUserId = 0;
        String comments = "";
        int productid = 0;
        OpStatus opStatus = null;

        try {
            for (OPAQueue q : firstRecords) {

                adminUserId = q.getCreatedBy();

                //TODO remove ContractValidationQueueJsonObject after setting ref
                ProductQueueJsonObject product = mapper.readValue(q.getJsonData(), ProductQueueJsonObject.class);
                //ArrayList<Integer> productsWithErrors = new ArrayList<Integer>();
                List<Integer> productIds = product.getProductIds();
                productid = productIds.get(0);
                currentUserId = product.getCurrentUserId();

                opStatus = operationUtil.handleDelete(productid, currentUserId, adminUserId, comments);

                if (opStatus != null && opStatus.getId() == OpStatus.PASS) {

                    q.setCompletionDate(new java.sql.Timestamp(Calendar.getInstance().getTime().getTime()));
                    q.setSuccess("1");

                } else {
                    q.setSuccess("0");
                    q.setErrorMsg(opStatus.getDescription());
                    q.setCompletionDate(new java.sql.Timestamp(Calendar.getInstance().getTime().getTime()));
                }

                opaQueueDao.updateRecord(q);

            }

        } catch (Exception ex) {
            //            utils.LogExceptionAndSendEmail("ReaderScheduler", ex);
            throw ex;
        } finally {

        }
        return firstRecords;
    }

    public List<OPAQueue> processAllCancelProducts(List<OPAQueue> firstRecords) throws Exception {
        ObjectMapper mapper = new ObjectMapper();

        int adminUserId = 0, currentUserId = 0;
        String comments = "";
        int productId = 0;
        OpStatus opStatus = null;

        try {
            for (OPAQueue q : firstRecords) {

                adminUserId = q.getCreatedBy();

                //TODO remove ContractValidationQueueJsonObject after setting ref
                ProductQueueJsonObject product = mapper.readValue(q.getJsonData(), ProductQueueJsonObject.class);
                //ArrayList<Integer> productsWithErrors = new ArrayList<Integer>();
                List<Integer> productIds = product.getProductIds();
                productId = productIds.get(0);
                currentUserId = product.getCurrentUserId();

                opStatus = operationUtil.handleCancel(productId, currentUserId, adminUserId, comments);

                if (opStatus != null && opStatus.getId() == OpStatus.PASS) {

                    q.setCompletionDate(new java.sql.Timestamp(Calendar.getInstance().getTime().getTime()));
                    q.setSuccess("1");

                } else {

                    q.setCompletionDate(new java.sql.Timestamp(Calendar.getInstance().getTime().getTime()));
                    q.setSuccess("0");
                    q.setErrorMsg(opStatus.getDescription());
                }

                opaQueueDao.updateRecord(q);

            }

        } catch (Exception ex) {
            //            utils.LogExceptionAndSendEmail("ReaderScheduler", ex);
            throw ex;
        } finally {

        }
        return firstRecords;
    }

    public List<OPAQueue> processAllApproveProducts(List<OPAQueue> firstRecords) throws Exception {
        ObjectMapper mapper = new ObjectMapper();

        int adminUserId = 0, currentUserId = 0;
        String comments = "";
        int productId = 0;
        OpStatus opStatus = null;

        try {
            for (OPAQueue q : firstRecords) {

                adminUserId = q.getCreatedBy();

                ProductQueueJsonObject product = mapper.readValue(q.getJsonData(), ProductQueueJsonObject.class);
                List<Integer> productIds = product.getProductIds();
                productId = productIds.get(0);
                currentUserId = product.getCurrentUserId();

                opStatus = operationUtil.handleApprove(productId, currentUserId, adminUserId, comments);

                if (opStatus != null && opStatus.getId() == OpStatus.PASS) {

                    q.setCompletionDate(new java.sql.Timestamp(Calendar.getInstance().getTime().getTime()));
                    q.setSuccess("1");

                } else {

                    q.setCompletionDate(new java.sql.Timestamp(Calendar.getInstance().getTime().getTime()));
                    q.setSuccess("0");
                    q.setErrorMsg(opStatus.getDescription());
                }

                opaQueueDao.updateRecord(q);

            }

        } catch (Exception ex) {
            //            utils.LogExceptionAndSendEmail("ReaderScheduler", ex);
            throw ex;
        } finally {

        }
        return firstRecords;
    }

    //Bulk Task Action

    public List<OPAQueue> processAllUnSuspendProducts(List<OPAQueue> firstRecords) throws Exception {
        ObjectMapper mapper = new ObjectMapper();

        int adminUserId = 0;
        String comments = "";
        int productId = 0;

        try {
            for (OPAQueue q : firstRecords) {

                adminUserId = q.getCreatedBy();
                ProductQueueJsonObject product = mapper.readValue(q.getJsonData(), ProductQueueJsonObject.class);
                //ArrayList<Integer> productsWithErrors = new ArrayList<Integer>();
                List<Integer> productIds = product.getProductIds();
                productId = productIds.get(0);
                comments = product.getComments();

                BulkTask[] bulkTasks = bulkTasksService.bulkUndoSuspendProducts(String.valueOf(productId), comments,
                        adminUserId);

                if (bulkTasks != null) {

                    if (bulkTasks[0].getStatus().equalsIgnoreCase("Success")) {

                        q.setCompletionDate(new java.sql.Timestamp(Calendar.getInstance().getTime().getTime()));
                        q.setSuccess("1");

                    } else {
                        q.setSuccess("0");
                        q.setCompletionDate(new java.sql.Timestamp(Calendar.getInstance().getTime().getTime()));
                        q.setErrorMsg(bulkTasks[0].getMessage());

                    }
                } else {
                    q.setSuccess("0");
                    q.setCompletionDate(new java.sql.Timestamp(Calendar.getInstance().getTime().getTime()));
                    q.setErrorMsg("Bulk Tasks is null  while processing   unSuspend");

                }
                opaQueueDao.updateRecord(q);

            }

        } catch (Exception ex) {
            //            utils.LogExceptionAndSendEmail("ReaderScheduler", ex);
            throw ex;
        } finally {

        }
        return firstRecords;
    }

    public List<OPAQueue> processAllUnApproveProducts(List<OPAQueue> firstRecords) throws Exception {
        ObjectMapper mapper = new ObjectMapper();

        int adminUserId = 0;
        String comments = "";
        int productId = 0;

        try {
            for (OPAQueue q : firstRecords) {

                adminUserId = q.getCreatedBy();

                //TODO remove ContractValidationQueueJsonObject after setting ref
                ProductQueueJsonObject product = mapper.readValue(q.getJsonData(), ProductQueueJsonObject.class);

                List<Integer> productIds = product.getProductIds();
                productId = productIds.get(0);
                comments = product.getComments();
                BulkTask[] bulkTasks = bulkTasksService.bulkUndoApproveProducts(String.valueOf(productId), comments,
                        adminUserId);

                if (bulkTasks != null) {

                    if (bulkTasks[0].getStatus().equalsIgnoreCase("Success")) {

                        q.setCompletionDate(new java.sql.Timestamp(Calendar.getInstance().getTime().getTime()));
                        q.setSuccess("1");

                    } else {
                        q.setSuccess("0");
                        q.setErrorMsg(bulkTasks[0].getMessage());
                        q.setCompletionDate(new java.sql.Timestamp(Calendar.getInstance().getTime().getTime()));

                    }
                } else {
                    q.setSuccess("0");
                    q.setErrorMsg("Bulk Task is null while processing  UnApprove");
                    q.setCompletionDate(new java.sql.Timestamp(Calendar.getInstance().getTime().getTime()));

                }
                opaQueueDao.updateRecord(q);

            }

        } catch (Exception ex) {
            //            utils.LogExceptionAndSendEmail("ReaderScheduler", ex);
            throw ex;
        } finally {

        }
        return firstRecords;
    }

    public List<OPAQueue> processAllUnCancelProducts(List<OPAQueue> firstRecords) throws Exception {
        ObjectMapper mapper = new ObjectMapper();

        int adminUserId = 0;
        String comments = "";
        int productId = 0;

        try {
            for (OPAQueue q : firstRecords) {

                adminUserId = q.getCreatedBy();

                ProductQueueJsonObject product = mapper.readValue(q.getJsonData(), ProductQueueJsonObject.class);
                //ArrayList<Integer> productsWithErrors = new ArrayList<Integer>();
                List<Integer> productIds = product.getProductIds();
                productId = productIds.get(0);
                comments = product.getComments();
                BulkTask[] bulkTasks = bulkTasksService.bulkUndoCancelProducts(String.valueOf(productId), comments,
                        adminUserId);

                if (bulkTasks != null) {

                    if (bulkTasks[0].getStatus().equalsIgnoreCase("Success")) {

                        q.setCompletionDate(new java.sql.Timestamp(Calendar.getInstance().getTime().getTime()));
                        q.setSuccess("1");

                    } else {

                        q.setCompletionDate(new java.sql.Timestamp(Calendar.getInstance().getTime().getTime()));
                        q.setSuccess("0");
                        q.setErrorMsg(bulkTasks[0].getMessage());

                    }
                } else {
                    q.setSuccess("0");
                    q.setCompletionDate(new java.sql.Timestamp(Calendar.getInstance().getTime().getTime()));
                    q.setErrorMsg("Bulk Task is null while processing UnCancel ");

                }
                opaQueueDao.updateRecord(q);

            }

        } catch (Exception ex) {
            //            utils.LogExceptionAndSendEmail("ReaderScheduler", ex);
            throw ex;
        } finally {

        }
        return firstRecords;
    }

    public List<OPAQueue> processAllSuspendProducts(List<OPAQueue> firstRecords) throws Exception {
        ObjectMapper mapper = new ObjectMapper();

        int adminUserId = 0;
        String comments = "";
        int productId = 0;

        try {
            for (OPAQueue q : firstRecords) {

                adminUserId = q.getCreatedBy();

                ProductQueueJsonObject product = mapper.readValue(q.getJsonData(), ProductQueueJsonObject.class);
                List<Integer> productIds = product.getProductIds();
                productId = productIds.get(0);
                comments = product.getComments();
                BulkTask[] bulkTasks = bulkTasksService.bulkSuspendProducts(String.valueOf(productId), comments,
                        adminUserId);

                if (null != bulkTasks) {

                    if (bulkTasks[0].getStatus().equalsIgnoreCase("Success")) {

                        q.setCompletionDate(new java.sql.Timestamp(Calendar.getInstance().getTime().getTime()));
                        q.setSuccess("1");

                    } else {

                        q.setCompletionDate(new java.sql.Timestamp(Calendar.getInstance().getTime().getTime()));
                        q.setSuccess("0");
                        q.setErrorMsg(bulkTasks[0].getMessage());

                    }
                } else {
                    q.setSuccess("0");
                    q.setCompletionDate(new java.sql.Timestamp(Calendar.getInstance().getTime().getTime()));
                    q.setErrorMsg("Bulk Task is null while processing Suspend ");
                }

                opaQueueDao.updateRecord(q);

            }

        } catch (Exception ex) {
            //            utils.LogExceptionAndSendEmail("ReaderScheduler", ex);
            throw ex;
        } finally {

        }
        return firstRecords;

    }

    //DPW
    public List<OPAQueue> processAllApproveExternallyProducts(List<OPAQueue> firstRecords) throws Exception {
        ObjectMapper mapper = new ObjectMapper();

        int adminUserId = 0;
        String comments = "";
        int productId = 0;

        try {
            for (OPAQueue q : firstRecords) {

                adminUserId = q.getCreatedBy();

                //TODO remove ContractValidationQueueJsonObject after setting ref
                ProductQueueJsonObject product = mapper.readValue(q.getJsonData(), ProductQueueJsonObject.class);
                List<Integer> productIds = product.getProductIds();
                comments = product.getComments();
                productId = productIds.get(0);
                BulkTask[] bulkTasks = bulkTasksService.bulkApproveProductsExternally(String.valueOf(productId),
                        comments, adminUserId);

                if (null != bulkTasks) {
                    if (bulkTasks[0].getStatus().equalsIgnoreCase("Success")) {

                        q.setCompletionDate(new java.sql.Timestamp(Calendar.getInstance().getTime().getTime()));
                        q.setSuccess("1");

                    } else {
                        q.setSuccess("0");
                        q.setErrorMsg(bulkTasks[0].getMessage());
                        q.setCompletionDate(new java.sql.Timestamp(Calendar.getInstance().getTime().getTime()));

                    }
                } else {

                    q.setSuccess("0");
                    q.setCompletionDate(new java.sql.Timestamp(Calendar.getInstance().getTime().getTime()));
                    q.setErrorMsg("Bulk Task is null while processing DPW ");

                }

                opaQueueDao.updateRecord(q);

            }

        } catch (Exception ex) {
            //utils.LogExceptionAndSendEmail("ReaderScheduler", ex);
            throw ex;
        } finally {

        }
        return firstRecords;
    }

    //Reassign
    public List<OPAQueue> processAllReassignProducts(List<OPAQueue> firstRecords) throws Exception {
        ObjectMapper mapper = new ObjectMapper();

        OpStatus opStatus = null;
        int adminUserId = 0;
        String comments = "";
        int productId = 0;
        int currentUserId = 0;
        int recipientUserId = 0;

        try {
            for (OPAQueue q : firstRecords) {

                adminUserId = q.getCreatedBy();

                ProductQueueJsonObject product = mapper.readValue(q.getJsonData(), ProductQueueJsonObject.class);
                List<Integer> productIds = product.getProductIds();
                productId = productIds.get(0);
                comments = product.getComments();
                recipientUserId = product.getRecipientUserId();
                currentUserId = product.getCurrentUserId();
                try {
                    opStatus = operationUtil.handleReassign(productId, currentUserId, recipientUserId, adminUserId,
                            comments);
                } catch (Exception ex) {
                    // Reassign Failed
                    opStatus = new OpStatus(OpStatus.UNKNOWN, "Reassign Failed.");
                }
                if (opStatus != null && opStatus.getId() == OpStatus.PASS) {

                    q.setCompletionDate(new java.sql.Timestamp(Calendar.getInstance().getTime().getTime()));
                    q.setSuccess("1");
                } else {

                    q.setCompletionDate(new java.sql.Timestamp(Calendar.getInstance().getTime().getTime()));
                    q.setSuccess("0");
                    q.setErrorMsg(opStatus.getDescription());
                }

                opaQueueDao.updateRecord(q);

            }

        } catch (Exception ex) {
            //utils.LogExceptionAndSendEmail("ReaderScheduler", ex);
            throw ex;
        } finally {

        }
        return firstRecords;
    }

    public List<OPAQueue> processAllCreateHardStopProducts(List<OPAQueue> firstRecords) throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        try {
            for (OPAQueue q : firstRecords) {

                ProductQueueJsonObject jsonProduct = mapper.readValue(q.getJsonData(),
                        ProductQueueJsonObject.class);

                String sProduct = jsonProduct.getProductId();
                String reason = jsonProduct.getReason();
                int currentUserId = jsonProduct.getCurrentUserId();
                int objectTypeId = jsonProduct.getObjectTypeId();
                int hardStopType = jsonProduct.getHardStopType();
                String comments = jsonProduct.getComments();
                User user = userService.get(currentUserId, 1);
                String[] sProductIds = sProduct.split(",");

                boolean returnFlag = false;

                for (int i = 0; i < sProductIds.length; i++) {
                    // MUST trim away whitespace to productIds (or else parse errs)
                    returnFlag = contractService.createProductComplianceExemption(
                            Long.parseLong(sProductIds[i].trim()), objectTypeId, reason, user, hardStopType,
                            comments);
                }

                if (returnFlag) {

                    q.setCompletionDate(new java.sql.Timestamp(Calendar.getInstance().getTime().getTime()));
                    q.setSuccess("1");

                } else {
                    q.setCompletionDate(new java.sql.Timestamp(Calendar.getInstance().getTime().getTime()));
                    q.setSuccess("0");
                    q.setErrorMsg(" Error occured while processing Create HardStop Products ");
                }
                opaQueueDao.updateRecord(q);

            }

        } catch (Exception ex) {
            //utils.LogExceptionAndSendEmail("ReaderScheduler", ex);
            throw ex;
        } finally {

        }
        return firstRecords;
    }

    public List<OPAQueue> processAllRemoveHardStopProducts(List<OPAQueue> firstRecords) throws Exception {
        ObjectMapper mapper = new ObjectMapper();

        try {
            for (OPAQueue q : firstRecords) {

                ProductQueueJsonObject jsonProduct = mapper.readValue(q.getJsonData(),
                        ProductQueueJsonObject.class);
                String sProduct = jsonProduct.getProductId();
                int currentUserId = jsonProduct.getCurrentUserId();
                int hardStopType = jsonProduct.getHardStopType();
                String comments = jsonProduct.getComments();
                User user = userService.get(currentUserId, 1);
                String[] sProductIds = sProduct.split(",");

                boolean returnFlag = false;
                for (int i = 0; i < sProductIds.length; i++) {
                    // MUST trim away whitespace to productIds (or else parse errs)
                    returnFlag = contractService.removeProductComplianceExemption(
                            Long.parseLong(sProductIds[i].trim()), hardStopType, user, comments);
                }

                if (returnFlag) {

                    q.setCompletionDate(new java.sql.Timestamp(Calendar.getInstance().getTime().getTime()));
                    q.setSuccess("1");

                } else {

                    q.setCompletionDate(new java.sql.Timestamp(Calendar.getInstance().getTime().getTime()));
                    q.setSuccess("0");
                    q.setErrorMsg(" Error occured while processing Remove Hard Stop");
                }

                opaQueueDao.updateRecord(q);

            } // for

        } catch (Exception ex) {

            //utils.LogExceptionAndSendEmail("ReaderScheduler", ex);
            throw ex;
        } finally {

        }
        return firstRecords;
    }

    public List<OPAQueue> processAllCreateHardStopLicensees(List<OPAQueue> firstRecords) throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        try {
            for (OPAQueue q : firstRecords) {
                LicenseeQueueJsonObject jsonQueue = mapper.readValue(q.getJsonData(),
                        LicenseeQueueJsonObject.class);

                String sLicensee = jsonQueue.getLicenseeId();
                int currentUserId = jsonQueue.getCurrentUserId();
                int objectTypeId = jsonQueue.getObjectTypeId();
                int hardStopType = jsonQueue.getHardStopType();
                User user = userService.get(currentUserId, 1);
                String[] sLicenseeIds = sLicensee.split(",");

                boolean returnFlag = false;
                String msg = "Error occured while processing Create Hard Stop for Licensee.";
                for (int i = 0; i < sLicenseeIds.length; i++) {
                    try {
                        // MUST trim away whitespace to productIds (or else parse errs)
                        returnFlag = contractService.createLicenseeComplianceExemption(
                                Long.parseLong(sLicenseeIds[i].trim()), objectTypeId, user, hardStopType);
                    } catch (NumberFormatException nfe) {
                        msg += "  Problem with Licensee ID: " + sLicenseeIds[i] + ".  " + nfe.getMessage();
                    } catch (Exception e) {
                        msg += "  " + e.getMessage();
                    }
                }

                if (returnFlag) {
                    q.setSuccess("1");
                } else {
                    q.setSuccess("0");
                    q.setErrorMsg(msg);
                }
                q.setCompletionDate(new java.sql.Timestamp(Calendar.getInstance().getTime().getTime()));

                opaQueueDao.updateRecord(q);

            }
        } catch (Exception ex) {
            //utils.LogExceptionAndSendEmail("ReaderScheduler", ex);
            throw ex;
        } finally {
            // nothing to do here
        }
        return firstRecords;
    }

    public List<OPAQueue> processAllRemoveHardStopLicensees(List<OPAQueue> firstRecords) throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        try {
            for (OPAQueue q : firstRecords) {
                LicenseeQueueJsonObject jsonQueue = mapper.readValue(q.getJsonData(),
                        LicenseeQueueJsonObject.class);

                String sLicensee = jsonQueue.getLicenseeId();
                int currentUserId = jsonQueue.getCurrentUserId();
                int objectTypeId = jsonQueue.getObjectTypeId();
                User user = userService.get(currentUserId, 1);
                String[] sLicenseeIds = sLicensee.split(",");

                boolean returnFlag = false;
                String msg = "Error occured while processing Remove Hard Stop for Licensee.";
                for (int i = 0; i < sLicenseeIds.length; i++) {
                    try {
                        // MUST trim away whitespace to productIds (or else parse errs)
                        returnFlag = contractService.removeLicenseeComplianceExemption(
                                Long.parseLong(sLicenseeIds[i].trim()), objectTypeId, user);
                    } catch (NumberFormatException nfe) {
                        msg += "  Problem with Licensee ID: " + sLicenseeIds[i] + ".  " + nfe.getMessage();
                    } catch (Exception e) {
                        msg += "  " + e.getMessage();
                    }
                }

                if (returnFlag) {
                    q.setSuccess("1");
                } else {
                    q.setSuccess("0");
                    q.setErrorMsg(msg);
                }
                q.setCompletionDate(new java.sql.Timestamp(Calendar.getInstance().getTime().getTime()));

                opaQueueDao.updateRecord(q);
            }
        } catch (Exception ex) {
            //utils.LogExceptionAndSendEmail("ReaderScheduler", ex);
            throw ex;
        } finally {
            // nothing to do here
        }
        return firstRecords;
    }

    //public List<Integer> getPolicyDeltasList() {
    //   return policyDeltasList;
    //}

    //public void setPolicyDeltasList(List<Integer> policyDeltasList) {
    //   this.policyDeltasList = policyDeltasList;
    //}

}