Skip to main content

Determining the Number of Accounts

In this document, we will explain the process of determining the number of accounts based on various filters. The process involves initializing an AccountsResource object, calling different methods depending on the provided filter, and parsing the response to count the number of accounts.

The flow starts by initializing an AccountsResource object. Depending on the filter provided, different methods are called to retrieve account details. For example, if the filter contains ACCOUNT_AVAILABLE_BALANCE, it retrieves accounts based on balance. If the filter contains ACCOUNT_NUMBER, it retrieves accounts based on account number. If the filter contains ACCOUNT_CUSTOMER_NUMBER, it retrieves accounts based on customer number. If no filter is provided, it retrieves all accounts. Finally, the response is parsed to count the number of accounts.

Here is a high level diagram of the flow, showing only the most important functions:

Flow drill down

First, we'll zoom into this section of the flow:


howMany function

The howMany function determines the number of accounts based on various filters. It initializes an AccountsResource object and uses it to call different methods depending on the filter provided. For example, if the filter contains ACCOUNT_AVAILABLE_BALANCE, it calls getAccountsByBalanceWithOffsetAndLimitExternal. If the filter contains ACCOUNT_NUMBER, it calls getAccountExternal. If the filter contains ACCOUNT_CUSTOMER_NUMBER, it calls getAccountsByCustomerExternal. If no filter is provided, it calls getAccountsExternal to get all accounts. The function then parses the response to count the number of accounts.

	public int howMany(String filter)
{

// AND ACCOUNT_NUMBER = 0000000024
// AND ACCOUNT_CUSTOMER_NUMBER

AccountsResource myAccountsResource = new AccountsResource();
Response myAccountsResponse = null;
this.count = 0;

try
{
if (filter.contains("AND ACCOUNT_AVAILABLE_BALANCE"))
{
// 01234567890123456789012345678901234567890
// AND ACCOUNT_AVAILABLE_BALANCE <= 33558.0

String operator = filter.substring(31, 32);
BigDecimal balance = BigDecimal
.valueOf(Double.parseDouble(filter.substring(34)));



getAccountsByCustomerExternal function

The getAccountsByCustomerExternal function retrieves accounts owned by a specified customer. It calls the getAccountsByCustomerInternal function to get the account details and then terminates the HBankDataAccess object before returning the response.

	@GET
@Path("/retrieveByCustomerNumber/{customerNumber}")
@Produces("application/json")
public Response getAccountsByCustomerExternal(
@PathParam(JSON_CUSTOMER_NUMBER) Long customerNumber,
@QueryParam("countOnly") Boolean countOnly)
{
/** This will list accounts owned by a specified customer */
logger.entering(this.getClass().getName(),
"getAccountsByCustomerExternal(Long customerNumber, Boolean countOnly)");

Response myResponse = getAccountsByCustomerInternal(customerNumber);
HBankDataAccess myHBankDataAccess = new HBankDataAccess();
myHBankDataAccess.terminate();
logger.exiting(this.getClass().getName(),
"getAccountsByCustomerExternal(Long customerNumber, Boolean countOnly)",
myResponse);
return myResponse;
}


getAccountsExternal function

The getAccountsExternal function returns a fixed number of accounts based on the provided limit and offset. It calls the getAccountsInternal function to get the account details and then terminates the HBankDataAccess object before returning the response.

	@GET
@Produces("application/json")
public Response getAccountsExternal(@QueryParam("limit") Integer limit,
@QueryParam("offset") Integer offset,
@QueryParam("countOnly") Boolean countOnly)
{
// This method returns a fixed number of accounts, up to limit "limit",
// starting at offset "offset"
logger.entering(this.getClass().getName(),
"getAccountsExternal(Integer limit, Integer offset,Boolean countOnly)");
boolean countOnlyReal = false;
if (countOnly != null)
{
countOnlyReal = countOnly.booleanValue();
}
Response myResponse = getAccountsInternal(limit, offset, countOnlyReal);
HBankDataAccess myHBankDataAccess = new HBankDataAccess();
myHBankDataAccess.terminate();
logger.exiting(this.getClass().getName(),
"getAccountsExternal(Integer limit, Integer offset,Boolean countOnly)",
myResponse);


getAccountsInternal function

The getAccountsInternal function retrieves account details from the database. It checks if only the count of accounts is needed or if the actual account details are required. If the count is needed, it calls getAccountsCountOnly. Otherwise, it retrieves the account details and constructs a JSON response with the account information.

	public Response getAccountsInternal(Integer limit, Integer offset,
boolean countOnly)
{
logger.entering(this.getClass().getName(),
"getAccountsInternal(Integer limit, Integer offset,boolean countOnly)");
Response myResponse = null;

com.ibm.cics.cip.bankliberty.web.db2.Account db2Account = null;
JSONObject response = new JSONObject();
JSONArray accounts = null;
int numberOfAccounts = 0;
Integer sortCode = this.getSortCode();
// We want to set a limit to try to avoid OutOfMemory Exceptions.
// 250,000 seems a bit large
if (limit == null)
{
limit = 250000;
}
if (limit == 0)
{
limit = 250000;


getAccountsByCustomerInternal function

The getAccountsByCustomerInternal function retrieves accounts for a specific customer from the database. It first checks if the customer exists by calling getCustomerInternal. If the customer exists, it retrieves the account details and constructs a JSON response with the account information.

	public Response getAccountsByCustomerInternal(
@PathParam(JSON_CUSTOMER_NUMBER) Long customerNumber)
{
logger.entering(this.getClass().getName(),
GET_ACCOUNTS_BY_CUSTOMER_INTERNAL);

JSONArray accounts = null;
Response myResponse = null;

JSONObject response = new JSONObject();
Integer sortCode = this.getSortCode();
int numberOfAccounts = 0;

CustomerResource myCustomer = new CustomerResource();
Response customerResponse = myCustomer
.getCustomerInternal(customerNumber);

if (customerResponse.getStatus() != 200)
{
if (customerResponse.getStatus() == 404)
{

Now, lets zoom into this section of the flow:


Handling account retrieval based on balance

First, the getAccountsByBalanceWithOffsetAndLimitExternal method is called to handle the external request for retrieving accounts based on balance. It logs the entry, processes the countOnly parameter, and delegates the main logic to getAccountsByBalanceWithOffsetAndLimitInternal.

	@GET
@Path("/balance")
@Produces("application/json")
public Response getAccountsByBalanceWithOffsetAndLimitExternal(
@QueryParam("balance") BigDecimal balance,
@QueryParam("operator") String operator,
@QueryParam("offset") Integer offset,
@QueryParam("limit") Integer limit,
@QueryParam("countOnly") Boolean countOnly)
{
// return only accounts with a certain balance
logger.entering(this.getClass().getName(),
"getAccountsByBalanceWithOffsetAndLimitExternal(BigDecimal balance, String operator, Integer offset, Integer limit, Boolean countOnly");
boolean countOnlyReal = false;
if (countOnly != null)
{
countOnlyReal = countOnly.booleanValue();
}

Response myResponse = getAccountsByBalanceWithOffsetAndLimitInternal(
balance, operator, offset, limit, countOnlyReal);


Next, the getAccountsByBalanceWithOffsetAndLimitInternal method validates the operator, sets default values for offset and limit, and decides whether to count only or retrieve full account details. It then calls the appropriate method in the Account class to fetch the data.

	public Response getAccountsByBalanceWithOffsetAndLimitInternal(
@QueryParam("balance") BigDecimal balance,
@QueryParam("operator") String operator,
@QueryParam("offset") Integer offset,
@QueryParam("limit") Integer limit, boolean countOnly)
{
// return only accounts with a certain balance
logger.entering(this.getClass().getName(),
GET_ACCOUNTS_BY_BALANCE_WITH_OFFSET_AND_LIMIT_INTERNAL);
Response myResponse = null;
boolean lessThan;
if (!operator.startsWith("<") && !(operator.startsWith(">")))
{
JSONObject error = new JSONObject();
error.put(JSON_ERROR_MSG, "Invalid operator, '" + operator
+ "' only <= or >= allowed");
logger.log(Level.WARNING, () -> "Invalid operator, '" + operator
+ "' only <= or >= allowed");
logger.exiting(this.getClass().getName(),
GET_ACCOUNTS_BY_BALANCE_WITH_OFFSET_AND_LIMIT_INTERNAL,
myResponse);


Then, the getAccountsByBalance method in the Account class constructs and executes the SQL query to retrieve account details based on the balance criteria. It processes the result set and returns the account data.

	public Account[] getAccountsByBalance(Integer sortCode2, BigDecimal balance,
boolean lessThan)
{
logger.entering(this.getClass().getName(), GET_ACCOUNTS_BY_BALANCE);
openConnection();
Account[] temp = new Account[250000];
int i = 0;
StringBuilder myStringBuilder = new StringBuilder();

for (i = sortCode2.toString().length(); i < SORT_CODE_LENGTH; i++)
{
myStringBuilder.append('0');
}

myStringBuilder.append(sortCode2.toString());

String sortCodeString = myStringBuilder.toString();
String sql = "SELECT * from ACCOUNT where ACCOUNT_EYECATCHER LIKE 'ACCT' AND ACCOUNT_SORTCODE like ? ";
if (lessThan)
{
sql = sql.concat(SQL_LESS_THAN);


Alternatively, if only the count of accounts is needed, the getAccountsByBalanceCountOnly method constructs and executes a SQL query to count the accounts matching the balance criteria and returns the count.

	public int getAccountsByBalanceCountOnly(Integer sortCode2,
BigDecimal balance, boolean lessThan)
{
logger.entering(this.getClass().getName(),
GET_ACCOUNTS_BY_BALANCE_COUNT_ONLY);

int accountCount = 0;
openConnection();

String sortCodeString = padSortCode(sortCode2);
String sql = "SELECT COUNT(*) AS ACCOUNT_COUNT from ACCOUNT where ACCOUNT_EYECATCHER LIKE 'ACCT' AND ACCOUNT_SORTCODE like ?";
if (lessThan)
{
sql = sql.concat(SQL_LESS_THAN);
}
else
{
sql = sql.concat(SQL_MORE_THAN);
}

try (PreparedStatement stmt = conn.prepareStatement(sql);)


Finally, the openConnection method in HBankDataAccess ensures a connection to the DB2 database is established, either by reusing an existing connection or creating a new one if necessary.

	protected void openConnection()
{
// Open a connection to the DB2 database
logger.entering(this.getClass().getName(), "openConnection()");

Integer taskNumberInteger = Task.getTask().getTaskNumber();
String db2ConnString = DB2CONN.concat(taskNumberInteger.toString());
logger.log(Level.FINE,
() -> "Attempting to get DB2CONN for task number "
+ taskNumberInteger.toString());
this.conn = (Connection) cornedBeef.get(db2ConnString);
if (this.conn == null)
{
HBankDataAccess.incrementConnCount();
logger.log(Level.FINE,
() -> "Attempting to create DB2CONN for task number "
+ taskNumberInteger.toString());
// Attempt to open a connection
openConnectionInternal();
logger.log(Level.FINE,
() -> "Creation succcessful for DB2CONN for task number "

Where is this flow used?

This flow is used multiple times in the codebase as represented in the following diagram:

 

This is an auto-generated document by Swimm 🌊 and has not yet been verified by a human