# (DD21) Business Logic — OwnerController.processFindForm() [26 LOC]

| Field | Value |
|-------|-------|
| Fully Qualified Name | `org.springframework.samples.petclinic.owner.OwnerController` |
| Layer | Controller |
| Module | `owner` (Package: `org.springframework.samples.petclinic.owner`) |

## 1. Role

### OwnerController.processFindForm()

This method implements the owner search entry point for the PetClinic owner module. It accepts the search criteria submitted from the owner find screen, normalizes the last-name input, and then executes a paginated lookup against the owner repository. From a business perspective, it decides which user journey should follow the search request: return to the search form with a validation-style message when no owners match, redirect directly to the owner detail page when exactly one owner matches, or render a paginated owner list when multiple matches exist.

The method acts as a routing and dispatch controller for search outcomes rather than as a data-processing utility. Its logic is centered on a single business dimension, owner last name, and it treats a blank last name as the broadest possible search request so that the `/owners` endpoint can return all owners even when no search text is supplied. The method also coordinates presentation concerns by updating the Spring MVC `Model` for list results and by rejecting the `lastName` field in `BindingResult` when the search returns no data. Overall, it is the bridge between the owner search form and the downstream list/detail views.

## 2. Processing Pattern (Detailed Business Logic)

```mermaid
flowchart TD
    START["processFindForm(page, owner, result, model)"]
    A["Read owner.getLastName()"]
    B{"lastName == null?"}
    C["Set lastName = \"\""]
    D["Call findPaginatedForOwnersLastName(page, lastName)"]
    E{"ownersResults.isEmpty()?"}
    F["Reject lastName on BindingResult with notFound message"]
    G["Return owners/findOwners view"]
    H{"ownersResults.getTotalElements() == 1?"}
    I["Select single Owner from ownersResults.iterator().next()"]
    J["Return redirect:/owners/ + owner.getId()"]
    K["Call addPaginationModel(page, model, ownersResults)"]
    L["Return owners/ownersList view"]
    END_NODE["Return / Next"]

    START --> A
    A --> B
    B -->|Yes| C
    B -->|No| D
    C --> D
    D --> E
    E -->|Yes| F
    F --> G
    G --> END_NODE
    E -->|No| H
    H -->|Yes| I
    I --> J
    J --> END_NODE
    H -->|No| K
    K --> L
    L --> END_NODE
```

## 3. Parameter Analysis

| No | Parameter Name | Type | Business Description |
|----|---------------|------|---------------------|
| 1 | `page` | `@RequestParam(defaultValue = "1") int` | The requested result page number for owner search pagination. A value of `1` means the first page of search results; larger values request later pages of the same owner search result set. |
| 2 | `owner` | `Owner` | The search form backing object that carries the owner criteria, primarily the last name entered by the user. The method reads `owner.getLastName()` to determine the lookup prefix. |
| 3 | `result` | `BindingResult` | The MVC validation and field error container for the search criteria. It is used here to register a `lastName` field error when the search returns no owners. |
| 4 | `model` | `Model` | The Spring MVC model used to pass pagination metadata and the owner list to the results view when multiple owners are found. |

**Instance fields / external state read by the method:**
- No controller instance field is read directly in this method.
- The method depends on the private helper `findPaginatedForOwnersLastName(page, lastName)` to query the repository-backed owner data set.
- The method depends on the private helper `addPaginationModel(page, model, ownersResults)` to populate the model for the list view.
- The method implicitly relies on repository state through the helper method, which uses `owners.findByLastNameStartingWith(...)`.

## 4. CRUD Operations / Called Services

### Pre-computed evidence from code analysis graph:

| CRUD | SC / CBS | SC Code | Entity / DB | Operation Description |
|------|----------|---------|-------------|----------------------|
| C | `OwnerController.addPaginationModel` | OwnerController | - | Calls `addPaginationModel` in `OwnerController` |
| R | `OwnerController.findPaginatedForOwnersLastName` | OwnerController | - | Calls `findPaginatedForOwnersLastName` in `OwnerController` |
| C | `VetController.addPaginationModel` | VetController | - | Calls `addPaginationModel` in `VetController` |

### Analysis for this method

| CRUD | SC / CBS | SC Code | Entity / DB | Operation Description |
|------|----------|---------|-------------|----------------------|
| R | `OwnerController.findPaginatedForOwnersLastName` | OwnerController | `Owner` repository / owner table via repository query | Reads owner records whose last name starts with the supplied search text and returns a paginated result set. |
| C | `BindingResult.rejectValue` | Spring MVC | - | Registers a user-facing field error on `lastName` when no owners match the search criteria. |
| R | `Page.isEmpty` / `Page.getTotalElements` / `Page.iterator` | Spring Data `Page` | `Owner` result page | Reads pagination metadata and inspects the search result set to decide which business branch to follow. |
| C | `OwnerController.addPaginationModel` | OwnerController | - | Populates the MVC model with pagination fields and the list of owners for the results page. |

## 5. Dependency Trace

| # | Caller (Screen/Batch) | Call Chain (Full Path to this Method) | Terminal (SC / CRUD / Entity) |
|---|----------------------|--------------------------------------|-------------------------------|
| 1 | Screen: owner find page (`/owners/find`) | Browser submit or direct GET `/owners` -> Spring MVC `OwnerController.processFindForm` | `findPaginatedForOwnersLastName [R] Owner repository` |
| 2 | Screen: owner search results branch for multiple matches | Browser submit or direct GET `/owners` -> Spring MVC `OwnerController.processFindForm` -> `addPaginationModel` | `addPaginationModel [C] MVC model attributes` |
| 3 | Screen: owner search results branch for no matches | Browser submit or direct GET `/owners` -> Spring MVC `OwnerController.processFindForm` -> `BindingResult.rejectValue` | `rejectValue [C] lastName field error` |
| 4 | Screen: owner search results branch for a single match | Browser submit or direct GET `/owners` -> Spring MVC `OwnerController.processFindForm` -> redirect response | `redirect:/owners/{id} [R] Owner detail endpoint` |

## 6. Per-Branch Detail Blocks

**Block 1** — [SEQUENCE] (L95-L98)

> Reads the search criteria and normalizes the last-name input so a blank request can still perform a broad owner lookup.

| # | Type | Code |
|---|------|------|
| 1 | EXEC | `String lastName = owner.getLastName();` // read submitted search criteria |

**Block 2** — [IF] `(lastName == null)` (L99)

> Normalizes a missing last name into an empty string so the search can match all owners.

| # | Type | Code |
|---|------|------|
| 1 | SET | `lastName = "";` // empty string signifies broadest possible search |

**Block 3** — [SEQUENCE] (L103-L104)

> Executes the paginated owner lookup using the normalized search text.

| # | Type | Code |
|---|------|------|
| 1 | CALL | `findPaginatedForOwnersLastName(page, lastName);` // query owners by last-name prefix |
| 2 | SET | `Page<Owner> ownersResults = ...;` // capture paginated search results |

**Block 4** — [IF] `(ownersResults.isEmpty())` (L105)

> Handles the no-match path by returning the search form with a field-level error.

| # | Type | Code |
|---|------|------|
| 1 | EXEC | `result.rejectValue("lastName", "notFound", "not found");` // mark lastName as not found |
| 2 | RETURN | `return "owners/findOwners";` // redisplay search form |

**Block 5** — [IF] `(ownersResults.getTotalElements() == 1)` (L111)

> Handles the exact-one-match path by redirecting directly to the matched owner detail page.

| # | Type | Code |
|---|------|------|
| 1 | SET | `owner = ownersResults.iterator().next();` // take the single matching owner |
| 2 | RETURN | `return "redirect:/owners/" + owner.getId();` // redirect to owner detail |

**Block 6** — [ELSE] `(multiple owners found)` (L117-L118)

> Handles the multi-match path by preparing pagination metadata and returning the owner list view.

| # | Type | Code |
|---|------|------|
| 1 | CALL | `addPaginationModel(page, model, ownersResults);` // populate list view model |
| 2 | RETURN | `return addPaginationModel(page, model, ownersResults);` // return owners list view |

## 7. Glossary

| Term | Type | Business Meaning |
|------|------|---------------------|
| `Owner` | Domain entity | PetClinic owner record representing a customer who owns one or more pets. |
| `lastName` | Field | Owner family name used as the search key in the owner find screen. |
| `page` | Field / parameter | Pagination page number requested by the user for search results. |
| `BindingResult` | Technical term | Spring MVC error container that stores validation and field-level rejection messages. |
| `Model` | Technical term | Spring MVC view model used to pass data to the rendered HTML page. |
| `findOwners` | View | The owner search form screen where users enter search criteria. |
| `ownersList` | View | The owner list results screen shown when multiple owners match the search criteria. |
| `redirect:/owners/{id}` | Routing term | Redirect to the owner detail screen for a single matched owner. |
| `paginate` | Business term | Split a large search result set into smaller pages for display. |
| `broadest possible search` | Business term | Search behavior that matches all owners when no last name is supplied. |
| `notFound` | Message code | Error key used to indicate that no owner matched the entered last name. |
| `OwnerRepository` | Repository | Data access component that queries owner persistence by last-name prefix. |
| `Page` | Framework term | Spring Data container holding one page of query results plus pagination metadata. |
| `getTotalElements` | Technical term | Counts the total number of records returned by the search across all pages. |
| `getTotalPages` | Technical term | Returns the number of pages required to display the full search result set. |
| `getContent` | Technical term | Returns the owners contained on the current page. |
| `Iterator` | Technical term | Used to retrieve the single result when exactly one owner is found. |
| `redirect` | Web term | HTTP navigation response that sends the browser to another endpoint. |
| `PetClinic` | Product term | Sample veterinary clinic application domain used in Spring demos. |
