/*
* The Kuali Financial System, a comprehensive financial management system for higher education.
*
* Copyright 2005-2014 The Kuali Foundation
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.kuali.kfs.module.bc.document.service;
import java.util.List;
import java.util.SortedSet;
import org.kuali.kfs.module.bc.BCConstants.LockStatus;
import org.kuali.kfs.module.bc.businessobject.BudgetConstructionFundingLock;
import org.kuali.kfs.module.bc.businessobject.BudgetConstructionHeader;
import org.kuali.kfs.module.bc.businessobject.BudgetConstructionLockStatus;
import org.kuali.kfs.module.bc.businessobject.BudgetConstructionLockSummary;
import org.kuali.kfs.module.bc.businessobject.BudgetConstructionPosition;
import org.kuali.kfs.module.bc.businessobject.PendingBudgetConstructionAppointmentFunding;
import org.kuali.kfs.module.bc.exception.BudgetConstructionLockUnavailableException;
import org.kuali.rice.kim.api.identity.Person;
/**
* This interface defines the methods that a LockService must provide. LockServiceImpl consists of methods that manage the various
* locks used in the Budget module. Locks are needed to serialize user updates since a BC Edoc is potentially editable by many users
* simultaneously and the default Optimistic locking scheme used by KFS would produce an inconsistent set of data. <B>Accountlock</B>
* controls exclusive access to the BC Edoc <B>Positionlock</B> controls exclusive access to a BC Position <B>Fundinglock</B>
* controls shared funding access. An associated Positionlock must exist before attempting to get a Fundinglock. Accountlock and
* Fundinglock are mutex. <B>Transactionlock</B> controls exclusive access to serialize updates to the accounting lines in the BC
* Edoc. A Fundinglock must exist before creating a Transactionlock. The Transactionlock lifecycle is short, required only for the
* duration of the accounting line update.
*/
public interface LockService {
/**
* This method attempts to lock the given Account for the passed in uuid. Finding an exising account lock for the uuid returns
* success without having to relock After setting an accountlock, if any funding locks are found, it releases the accountlock
* and sets BCLockStatus with LockStatus.FLOCK_FOUND. Accountlocks and Fundinglocks are mutex
*
* @param bcHeader
* @param principalId
* @return BudgetConstructionLockStatus with lockStatus.SUCCESS, OPTIMISTIC_EX (lost optimistic lock), FLOCK_FOUND (also sets
* fundingLocks), BY_OTHER (also sets accountLockOwner), NO_DOOR (null bcHeader)
*/
public BudgetConstructionLockStatus lockAccount(BudgetConstructionHeader bcHeader, String principalId);
/**
* This method checks the database for an accountlock. It assumes a valid bcHeader parameter
*
* @param bcHeader
* @return Returns true if locked, false if not locked or not found in the database
*/
public boolean isAccountLocked(BudgetConstructionHeader bcHeader);
/**
* This method checks the database for an accountlock according to the given appointment funding. It assumes a valid
* appointmentFunding parameter
*
* @param appointmentFunding the given appointment funding
* @return Returns true if locked, false if not locked or not found in the database
*/
public boolean isAccountLocked(PendingBudgetConstructionAppointmentFunding appointmentFunding);
/**
* Checks the given user has an account lock for the given document.
*
* @param chartOfAccountsCode - chart code of account lock
* @param accountNumber - account number of account lock
* @param subAccountNumber - sub account number of account lock
* @param fiscalYear - fiscal year of account lock
* @param principalId - lock user id
* @return true if locked, false if not locked or not found in the database
*/
public boolean isAccountLockedByUser(String chartOfAccountsCode, String accountNumber, String subAccountNumber, Integer fiscalYear, String principalId);
/**
* This method attempts to unlock the given BudgetConstructionHeader.
*
* @param bcHeader
* @return LockStatus.SUCCESS, NO_DOOR (not found), OPTIMISTIC_EX (lost optimistic lock)
*/
public LockStatus unlockAccount(BudgetConstructionHeader bcHeader);
/**
* This returns the set of BCFundingLocks associated with a BCHeader. The set is sorted by the Person name
*
* @param bcHeader
* @return SortedSet<BudgetConstructionFundingLock>
*/
public SortedSet<BudgetConstructionFundingLock> getFundingLocks(BudgetConstructionHeader bcHeader);
/**
* This method sets a funding lock associated to the header. It tests for an accountlock before/after to ensure there is no
* locking conflict. Finding an accountlock after setting a fundinglock causes the fundinglock to be released. account locks and
* funding locks are mutex. Finding a funding lock for the passed in uuid returns success without having to relock
*
* @param bcHeader
* @param principalId
* @return BudgetConstructionLockStatus with lockStatus.SUCCESS, BY_OTHER (accountlock found)
*/
public BudgetConstructionLockStatus lockFunding(BudgetConstructionHeader bcHeader, String principalId);
/**
* acquire a lock for the given appointment funding
*
* @param appointmentFunding the given appointment funding
* @param person the specified user
* @return BudgetConstructionLockStatus with lockStatus.SUCCESS, BY_OTHER (accountlock found)
*/
public BudgetConstructionLockStatus lockFunding(PendingBudgetConstructionAppointmentFunding appointmentFunding, Person person);
/**
* This removes the fundinglock for the account and user
*
* @param chartOfAccountsCode
* @param accountNumber
* @param subAccountNumber
* @param fiscalYear
* @param principalId
* @return LockStatus.SUCCESS, NO_DOOR (no fundinglock found)
*/
public LockStatus unlockFunding(String chartOfAccountsCode, String accountNumber, String subAccountNumber, Integer fiscalYear, String principalId);
/**
* release the lock for the given appointment funding if any
*
* @param appointmentFunding the given appointment funding that could have lock
* @param person the user who owns the lock on the given appointment funding
*/
public LockStatus unlockFunding(PendingBudgetConstructionAppointmentFunding appointmentFunding, Person person);
/**
* release the locks for the given appointment fundings if any
*
* @param lockedFundings the given appointment fundings that could have locks
* @param person the user who owns the locks on the given appointment fundings
*/
public void unlockFunding(List<PendingBudgetConstructionAppointmentFunding> lockedFundings, Person person);
/**
* Checks if the given user has a funding lock for the given accounting key.
*
* @param chartOfAccountsCode - chart code of funding lock
* @param accountNumber - account number of funding lock
* @param subAccountNumber - sub account number of funding lock
* @param fiscalYear - fiscal year of funding lock
* @param principalId - lock user id
* @return true if locked, false if not locked or not found in the database
*/
public boolean isFundingLockedByUser(String chartOfAccountsCode, String accountNumber, String subAccountNumber, Integer fiscalYear, String principalId);
/**
* This locks the position, meaning it sets the position lock id field with the puid. Finding the position already locked by the
* same user simply returns success.
*
* @param positionNumber
* @param fiscalYear
* @param principalId
* @return BudgetConstructionLockStatus with lockStatus.SUCCESS, OPTIMISTIC_EX (lost optimistic lock), BY_OTHER (also sets
* positionLockOwner), NO_DOOR (BudgetConstructionPosition found)
*/
public BudgetConstructionLockStatus lockPosition(String positionNumber, Integer fiscalYear, String principalId);
/**
* acquire a lock for the given budget position
*
* @param position the given position
* @param person the specified user
* @return BudgetConstructionLockStatus with lockStatus.SUCCESS, OPTIMISTIC_EX (lost optimistic lock), BY_OTHER (also sets
* positionLockOwner), NO_DOOR (BudgetConstructionPosition found)
*/
public BudgetConstructionLockStatus lockPosition(BudgetConstructionPosition position, Person person);
/**
* This checks the database for an existing positionlock
*
* @param positionNumber
* @param fiscalYear
* @return true or false (not locked or BudgetConstructionPosition not found)
*/
public boolean isPositionLocked(String positionNumber, Integer fiscalYear);
/**
* Checks the given user has an position lock for the given position number.
*
* @param positionNumber - position number of position record
* @param fiscalYear - fiscal year of position record
* @param principalId - lock user id
* @return true if locked, false if not locked or not found in the database
*/
public boolean isPositionLockedByUser(String positionNumber, Integer fiscalYear, String principalId);
/**
* Checks the given user has an position/funding lock for the given position number and accounting key.
*
* @param positionNumber - position number of position record
* @param chartOfAccountsCode - chart code of funding lock
* @param accountNumber - account number of funding lock
* @param subAccountNumber - sub account number of funding lock
* @param fiscalYear - fiscal year of position and funding record
* @param principalId - lock user id
* @return true if locked, false if not locked or not found in the database
*/
public boolean isPositionFundingLockedByUser(String positionNumber, String chartOfAccountsCode, String accountNumber, String subAccountNumber, Integer fiscalYear, String principalId);
/**
* This removes an existing positionlock
*
* @param positionNumber
* @param fiscalYear
* @return LockStatus.SUCCESS (success or already unlocked), OPTIMISTIC_EX (lost optimistic lock - unlikely), NO_DOOR
* (BudgetConstructionPosition not found)
*/
public LockStatus unlockPosition(String positionNumber, Integer fiscalYear);
/**
* release the locks on a positions with the given information
*
* @param positionNumber the given position number of a position
* @param fiscalYear the given fiscal year of a position
* @param person the specified user who owns the locks on the position
* @return LockStatus.SUCCESS (success or already unlocked), OPTIMISTIC_EX (lost optimistic lock - unlikely), NO_DOOR
* (BudgetConstructionPosition not found)
*/
public LockStatus unlockPosition(String positionNumber, Integer fiscalYear, String principalId);
/**
* release the lock for the given position if any
*
* @param position the given budget construction position that could have locks
* @param person the specified user who owns the lock on the given position
*/
public LockStatus unlockPostion(BudgetConstructionPosition position, Person person);
/**
* release the locks for the given positions if any
*
* @param lockedPositions the given budget construction positions that could have locks
* @param person the specified user who owns the locks on the given positions
*/
public void unlockPostion(List<BudgetConstructionPosition> lockedPositions, Person person);
/**
* This attempts a transactionlock on a BC Edoc for a pUId. It retries based on the setting of
* BCConstants.maxLockRetry.
*
* @param chartOfAccountsCode
* @param accountNumber
* @param subAccountNumber
* @param fiscalYear
* @param principalId
* @return BudgetConstructionLockStatus with lockStatus.SUCCESS, OPTIMISTIC_EX (lost optimistic lock - unlikely) BY_OTHER
* (retries exhausted, also sets transactionLockOwner), NO_DOOR (BudgetConstructionHeader not found)
*/
public BudgetConstructionLockStatus lockTransaction(String chartOfAccountsCode, String accountNumber, String subAccountNumber, Integer fiscalYear, String principalId);
/**
* attemps to have a transaction lock based on the information provided by the given funding line
*
* @param appointmentFunding the given appointment funding
* @param person the specified user
*/
public BudgetConstructionLockStatus lockTransaction(PendingBudgetConstructionAppointmentFunding appointmentFunding, Person person);
/**
* This checks the database for an existing transactionlock for the BC EDoc (account).
*
* @param chartOfAccountsCode
* @param accountNumber
* @param subAccountNumber
* @param fiscalYear
* @return true or false (not locked or BudgetConstructionHeader not found)
*/
public boolean isTransactionLocked(String chartOfAccountsCode, String accountNumber, String subAccountNumber, Integer fiscalYear);
/**
* Checks the given user has an transaction lock for the given document.
*
* @param chartOfAccountsCode - chart code of transaction lock
* @param accountNumber - account number of transaction lock
* @param subAccountNumber - sub account number of transaction lock
* @param fiscalYear - fiscal year of transaction lock
* @param principalId - lock user id
* @return true if locked, false if not locked or not found in the database
*/
public boolean isTransactionLockedByUser(String chartOfAccountsCode, String accountNumber, String subAccountNumber, Integer fiscalYear, String principalId);
/**
* This removes an existing transactionlock for a BC EDoc (account).
*
* @param chartOfAccountsCode
* @param accountNumber
* @param subAccountNumber
* @param fiscalYear
* @return LockStatus.SUCCESS (success or already unlocked), OPTIMISTIC_EX (lost optimistic lock - unlikely), NO_DOOR
* (BudgetConstructionHeader not found)
*/
public LockStatus unlockTransaction(String chartOfAccountsCode, String accountNumber, String subAccountNumber, Integer fiscalYear);
/**
* attemps to unlock a transaction based on the information provided by the given funding line
*
* @param appointmentFunding the given appointment funding
* @param person the specified user
*/
public void unlockTransaction(PendingBudgetConstructionAppointmentFunding appointmentFunding, Person person);
/**
* Retrieves all current account locks for the given user (or all locks if user is null/empty).
*
* @param lockUnivId - universal id that will be used in lock query
* @return budget headers that are locked
*/
public List<BudgetConstructionHeader> getAllAccountLocks(String lockUnivId);
/**
* Retrieves all current transaction locks for the given user (or all locks if user is null/empty).
*
* @param lockUnivId - universal id that will be used in lock query
* @return budget headers that are locked
*/
public List<BudgetConstructionHeader> getAllTransactionLocks(String lockUnivId);
/**
* Retrieves all funding locks that do not have a corresponding position lock for the given user (or all locks if user is
* null/empty).
*
* @param lockUnivId - universal id that will be used in lock query
* @return funding locks records
*/
public List<BudgetConstructionFundingLock> getOrphanedFundingLocks(String lockUnivId);
/**
* Retrieves all current position/funding locks for the given user (or all locks if user is null/empty).
*
* @param lockUnivId - universal id that will be used in lock query
* @return position/funding records that are locked.
*/
public List<PendingBudgetConstructionAppointmentFunding> getAllPositionFundingLocks(String lockUnivId);
/**
* Retrieves all current position locks without a funding lock for the given user (or all locks if user is null/empty).
*
* @param lockUnivId universal id that will be used in lock query
* @return positions that are locked.
*/
public List<BudgetConstructionPosition> getOrphanedPositionLocks(String lockUnivId);
/**
* Helper method to check if a lock exists for the given parameters.
*
* @param lockSummary - contains information about the record to unlock
* @return boolean true if lock exists, false otherwise
*/
public boolean checkLockExists(BudgetConstructionLockSummary lockSummary);
/**
* Helper method to check the lock type and do the unlock with the lock summary fields.
*
* @param lockSummary - contains information about the record to unlock
* @return LockStatus.SUCCESS, NO_DOOR (not found), OPTIMISTIC_EX (lost optimistic lock)
*/
public LockStatus doUnlock(BudgetConstructionLockSummary lockSummary);
/**
* determine whether the account lock on the given budget document is held by the the specified user
*
* @param budgetConstructionHeader the given budget document
* @param person the specified user
* @return true if the account lock on the given budget document is held by the the specified user; otherwise, false
*/
public boolean isAccountLockedByUser(BudgetConstructionHeader budgetConstructionHeader, Person person);
/**
* Retrieves account locks for funding records, for use in the payrate import process. Throws
* BudgetConstructionLockUnavailableException if new account lock is unavailable
*
* @param fundingRecords
* @param user
* @return
* @throws BudgetConstructionLockUnavailableException
*/
public List<PendingBudgetConstructionAppointmentFunding> lockPendingBudgetConstructionAppointmentFundingRecords(List<PendingBudgetConstructionAppointmentFunding> fundingRecords, Person user) throws BudgetConstructionLockUnavailableException;
/**
* Retrives an account lock (@see
* org.kuali.kfs.module.bc.document.service.LockService#lockAccount(org.kuali.kfs.module.bc.businessobject.BudgetConstructionHeader,
* java.lang.String) and commits the lock. Used by the request import process.
*
* @param bcHeader
* @param principalId
* @return
*/
public BudgetConstructionLockStatus lockAccountAndCommit(BudgetConstructionHeader bcHeader, String principalId);
/**
* Locks the position record for the given key if not already locked. Then retrieves all active funding lines for the position
* that are not marked as delete and attempts to lock each one.
*
* @param universityFiscalYear budget fiscal year, primary key field for position record
* @param positionNumber position number, primary key field for position record
* @param principalId current user requesting the lock
* @return <code>BudgetConstructionLockStatus</code> indicating the status of the lock attempt. Success is returned if all lock attempts were successful, else one of the Failure status codes are returned
*/
public BudgetConstructionLockStatus lockPositionAndActiveFunding(Integer universityFiscalYear, String positionNumber, String principalId);
/**
* Unlocks the position and all associated funding lines not marked as delete.
*
* @param universityFiscalYear budget fiscal year, primary key field for position record
* @param positionNumber position number, primary key field for position record
* @param principalId current user requesting the unlock
* @return <code>LockStatus</code> indicating the status of the unlock attempt.
*/
public LockStatus unlockPositionAndActiveFunding(Integer universityFiscalYear, String positionNumber, String principalId);
}