# KKW00816SFBean

## Purpose

`KKW00816SFBean` is the central **form backing bean** for a Japanese telecom/business service contract management screen within the X31C/X33V framework. It aggregates a large set of business fields — service codes, order types, status flags, timestamps, and customer-specific parameters — and exposes them through a uniform key-based data access protocol so that JSP pages and screen configuration XML files can bind to any field by string name. It holds both flat primitive values and two repeatable (list-based) data types for customer contracts and operation service contracts.

## Design

`KKW00816SFBean` plays multiple architectural roles simultaneously:

- **Form backing object** — It collects all request-scoped and view-scoped form data for the KKW00816 family of screens (KKW008160, KKW008170, KKW008180). The bean is typically created per HTTP request or stored in session scope and referenced by multiple JSPs.
- **Data access router** — Instead of forcing JSPs to call dozens of individual getters/setters, the bean exposes `loadModelData(key, subkey)`, `storeModelData(key, subkey, value)`, and `typeModelData(key, subkey)` methods. The `key` string identifies the field (e.g., `"申込種別コード"`) and the `subkey` ("value", "state", "enable") selects which aspect. For nested list items, the key uses a slash-delimited path like `"顧客契約引継リスト/0/value"`.
- **List-data manager** — Through the `X33VListedBeanInterface` contract, it supports dynamic addition, removal, and clearing of repeatable list items via `addListDataInstance`, `removeElementFromListData`, and `clearListDataInstance`.
- **Metadata reporter** — `listKoumokuIds` and `typeModelData` allow the framework to introspect the bean's field inventory and types at runtime, enabling generic form rendering and validation.

It extends `X33VViewBaseBean` (the framework's base view bean) and implements two additional interfaces: `X33VListedBeanInterface` (for list-data operations) and `X31CBaseBean` (for the key-based model access pattern). It also implements `Serializable` for session/HTTP persistence.

### Data model overview

The bean's fields fall into five categories:

1. **Repeatable list fields** — `cust_kei_hktgi_list_list` and `op_svc_kei_list_list`, each an `X33VDataTypeList` of typed bean instances (`KKW00816SF01DBean` / `KKW00816SF02DBean`).
2. **Flat scalar fields** — Dozens of `String` fields, each with an accompanying `_update` and `_state` variant. Some have a default value; many start empty.
3. **Enabled-flag fields** — `session_cnt_enabled`, `use_staymd_year_enabled`, `use_staymd_mon_enabled`, `use_staymd_day_enabled` — Boolean toggles for conditional form element enablement.
4. **Key-based accessors** — `loadModelData`, `storeModelData`, `typeModelData` — the three routing methods that dispatch to the appropriate getter/setter based on a string key.
5. **List-management utilities** — `listServiceFormIds`, `listKoumokuIds`, `addListDataInstance`, `removeElementFromListData`, `clearListDataInstance`.

### Field default values

Several fields are initialized at declaration:

| Field | Default Value |
|---|---|
| `mskm_sbt_cd_value` | `"00026"` |
| `op_svc_cd_value` | `"B015"` |
| `oya_kei_skbt_cd_value` | `"01"` |
| `work_param_id_session_uppl_value` | `"KK_SESSIONUPPL"` |
| `work_param_id_rsv_uppl_prd_value` | `"KK_RSVUPPLPRD"` |
| `rule0059_auto_aply_value` | `"0"` |
| `pplan_kotei_tanka_no_value` | `"123456789012"` |
| `session_cnt_value` | `"1"` |
| `order_sbt_cd_value` | `"1"` |
| `svc_order_cd_value` | `"06"` |
| `odr_hakko_joken_cd_value` | `"01"` |

The constructor initializes `cust_kei_hktgi_list_list` with exactly one pre-created `KKW00816SF01DBean` instance and initializes `op_svc_kei_list_list` as an empty list.

## Key Methods

### `loadModelData(String key, String subkey) → Object`

The central read-accessor. Given a `key` (the field identifier in Japanese) and a `subkey` (typically `"value"`, `"state"`, or `"enable"`), it dispatches to the appropriate getter:

- **Shared-bucket prefix** (`//`): If `key` starts with `"//"`, delegates to `super.loadCommonInfoData(key)`.
- **Root-level key** (no `/`): Looks up the field by full key name and returns the value for the given `subkey`.
- **List-item key** (`Key/Index/SubKey`): Parses the key by splitting on `/`. If `keyRemain` is `"*"`, returns the list size as `Integer`. Otherwise parses the index, bounds-checks it, and delegates into the nested bean's `loadModelData` with the remaining key and subkey.

Supported keys include (but are not limited to):

| Japanese Key | Field ID | Type | Notes |
|---|---|---|---|
| `顧客契約引継リスト` | cust_kei_hktgi_list | Data-type bean list | Repeatable |
| `オプションサービス契約リスト` | op_svc_kei_list | Data-type bean list | Repeatable |
| `申込種別コード` | mskm_sbt_cd | String | Default `"00026"` |
| `オプションサービスコード` | op_svc_cd | String | Default `"B015"` |
| `親契約識別コード` | oya_kei_skbt_cd | String | Default `"01"` |
| `業務パラメータID（セッション上限数）` | work_param_id_session_uppl | String | Default `"KK_SESSIONUPPL"` |
| `業務パラメータID（予約上限日数）` | work_param_id_rsv_uppl_prd | String | Default `"KK_RSVUPPLPRD"` |
| `事務手数料料自動適用可否` | rule0059_auto_aply | String | Default `"0"` |
| `料金コード` | pcrs_cd | String | |
| `料金プランコード` | pplan_cd | String | |
| `料金プラン固定単価番号` | pplan_kotei_tanka_no | String | Default `"123456789012"` |
| `初期マルチセッション認証IDパスワード` | shk_mltise_ninsho_id_pwd | String | |
| `マルチセッション認証ID` | mltise_ninsho_id | String | |
| `セッション数` | session_cnt | String / Long | Has `enable` subkey (Boolean) |
| `利用開始日（年）` | use_staymd_year | String | Has `enable` subkey |
| `利用開始日（月）` | use_staymd_mon | String | Has `enable` subkey |
| `利用開始日（日）` | use_staymd_day | String | Has `enable` subkey |
| `利用開始日` | use_staymd | String | |
| `サービス開始年月日` | svc_chrg_staymd | String | |
| `運用年月日` | unyo_ymd | String | |
| `運用年月日時分秒` | unyo_dtm | String | |
| `実施オプションサービス契約ステータス` | jssi_op_svc_kei_stat | String | |
| `サービス契約ステータス` | svc_kei_stat | String | |
| `お客様ステータス` | cust_stat | String | |
| `請求契約番号` | seiky_kei_no | String | |
| `進捗ステータス` | prg_stat | String | |
| `進捗特記事項1` | prg_tkjk_1 | String | |
| `オーダ種別コード` | order_sbt_cd | String | Default `"1"` |
| `サービスオーダコード` | svc_order_cd | String | Default `"06"` |
| `要求種別コード` | yokyu_sbt_cd | String | |
| `オーダ発行条件コード` | odr_hakko_joken_cd | String | Default `"01"` |
| `オーダ内容コード` | odr_naiyo_cd | String | |
| `オプションS/O/D登録実施` | op_sod_add_jssi | String | |
| `世代管理年月日時分秒（サービス契約）` | kk0081_gene_add_dtm | String | |
| `サービス契約内訳番号` | svc_kei_ucwk_no | String | |
| `世代管理年月日時分秒（サービス契約内訳）` | kk0161_gene_add_dtm | String | |
| `最終更新年月日時分秒` | last_upd_dtm | String | |
| `異動年月日時分秒` | ido_dtm | String | |
| `サービス契約内訳ステータス` | svc_kei_ucwk_stat | String | |

For the `session_cnt` key, the `value` subkey performs a Unicode substitution: any `−` (en-dash) characters in the stored value are replaced with the regular ASCII minus sign `'-'` before returning. This is necessary because Japanese system inputs often produce Unicode minus signs that the frontend expects as standard ASCII.

### `storeModelData(String key, String subkey, Object in_value)`

The write counterpart to `loadModelData`. The three-argument version delegates to the four-argument version with `isSetAsString = false`. The four-argument version:

- If `key` is `null`, returns immediately.
- If `subkey` is `null`, replaces it with `""`.
- If `key` starts with `"//"`, delegates to `super.storeCommonInfoData(key, in_value, isSetAsString)`.
- Otherwise, splits on `/` to identify the key element and dispatches to the corresponding setter. For list-item keys (`Key/Index/SubKey`), it parses the index and delegates into the nested bean's `storeModelData`.
- For scalar fields, it calls the appropriate getter/setter based on the `subkey` — `"value"` routes to the value setter, `"state"` routes to the state setter.
- For the `session_cnt` key with `isSetAsString = true`, if `in_value` is already a `String`, it stores it directly; otherwise, it casts to `Long` and converts to string.
- For `enable` subkeys, the Boolean value is cast and stored in the corresponding `_enabled` field.

### `typeModelData(String key, String subkey) → Class<?>`

Returns the Java type for a given key/subkey combination. This enables framework introspection:

- For list keys with `"*"` as the index, returns `Integer.class` (list size type).
- For data-type bean list keys (`顧客契約引継リスト`, `オプションサービス契約リスト`), delegates into the nested bean's `typeModelData`.
- For all shared scalar fields, returns `String.class` for `"value"` and `"state"` subkeys.
- For `session_cnt`, returns `Long.class` for `"value"` and `Boolean.class` for `"enable"`.
- For date fields with `enable` subkeys (`use_staymd_year`, `use_staymd_mon`, `use_staymd_day`), returns `Boolean.class`.

### `listKoumokuIds(String key) → ArrayList<String>`

Returns a list of all field keys supported by the bean. If `key` is `null`, returns the full list of 38 field names. If `key` starts with `"/"`, delegates to the superclass. If `key` matches a data-type bean list, returns that bean's `listKoumokuIds()` static method result. Otherwise, returns an empty list.

### `addListDataInstance(String key) → int`

Dynamically adds a new element to a repeatable list and returns the index of the newly added element. If `key` is `null`, returns `-1`. For shared-bucket keys starting with `"//"`, delegates to the superclass. For `顧客契約引継リスト`, creates a new `KKW00816SF01DBean` instance and appends it, respecting a maximum element count constraint. For `オプションサービス契約リスト`, creates a new `KKW00816SF02DBean` instance and appends without a hard max. Throws `X33SException` if the max element limit is exceeded for the customer contract list.

### `removeElementFromListData(String key, int index) → void`

Removes the element at the specified index from a repeatable list. Bounds-checks the index. Delegates to the superclass for shared-bucket keys. For `顧客契約引継リスト` and `オプションサービス契約リスト`, calls `list.remove(index)`.

### `clearListDataInstance(String key) → void`

Clears all elements from a repeatable list. Delegates to the superclass for shared-bucket keys. For the two data-type bean lists, calls `list.clear()`.

### `listServiceFormIds() → String[]`

Returns `null`. This method appears to be a framework hook that is not utilized in the current implementation.

### Constructor: `KKW00816SFBean()`

Initializes both list fields: `cust_kei_hktgi_list_list` is created with capacity 1 and pre-populated with one `KKW00816SF01DBean` instance; `op_svc_kei_list_list` is created as an empty `X33VDataTypeList`.

## Relationships

```mermaid
flowchart TD
    A["KKW00816SFBean
(Bean / View Data Container)"] --> B["KKW00816SF01DBean
(Custom Contract Item)"]
    A --> C["KKW00816SF02DBean
(Op. Service Contract Item)"]
    A --> D["X33VViewBaseBean
(Base Bean)"]
    A --> E["KKW008160PJP.jsp
(View Page)"]
    A --> F["KKW008160PJP.xml
(Screen Config)"]
    A --> G["KKW008170PJP.jsp
(View Page)"]
    A --> H["KKW008170PJP.xml
(Screen Config)"]
    A --> I["KKW008180PJP.xml
(Screen Config)"]
    style A fill:#e1f5fe,stroke:#01579b
    style B fill:#fff9c4,stroke:#f57f17
    style C fill:#fff9c4,stroke:#f57f17
    style D fill:#e8f5e9,stroke:#2e7d32
```

**Who uses KKW00816SFBean (5 inbound connections):**

| Consumer | Type | Relationship |
|---|---|---|
| `KKW008160PJP.jsp` | JSP view | References bean fields for form rendering |
| `KKW008160PJP.xml` | Screen config | Defines field binding configuration |
| `KKW008170PJP.jsp` | JSP view | References bean fields for form rendering |
| `KKW008170PJP.xml` | Screen config | Defines field binding configuration |
| `KKW008180PJP.xml` | Screen config | Defines field binding configuration |

**What KKW00816SFBean depends on (outbound):**

- `X33VViewBaseBean` — base class providing shared infrastructure (common info bucket handling, exception creation, shared model methods).
- `X33VListedBeanInterface` — interface for list data operations.
- `X31CBaseBean` — interface for key-based model access.
- `X33VDataTypeList` — generic typed list container for repeatable data-type beans.
- `KKW00816SF01DBean` — inner data-type bean for customer contract items.
- `KKW00816SF02DBean` — inner data-type bean for operation service contract items.
- `SelectItem` (JSF/facelets component) — used by `getJsflist_typelist_*` methods.
- `X33SException` — thrown by list data operations.
- `Serializable` — enables session persistence.

The bean has **no outbound Java field dependencies beyond its declared fields and framework classes** — it does not call external services or repositories directly.

## Usage Example

In the JSP pages that consume this bean, the typical pattern is:

```jsp
<!-- Bind a scalar field value -->
<bean:write name="kKW00816SFBean" property="mskm_sbt_cd_value" />

<!-- Access via the framework's model data protocol -->
<x33v:inputText beanName="kKW00816SFBean"
                key="申込種別コード"
                subkey="value" />

<!-- Access a field's state (for validation/display) -->
<x33v:inputText beanName="kKW00816SFBean"
                key="オプションサービスコード"
                subkey="state" />

<!-- Dynamic list item access -->
<x33v:repeatList beanName="kKW00816SFBean"
                 listKey="顧客契約引継リスト"
                 var="contractItem">
    <x33v:inputText beanName="contractItem"
                    key="value"
                    subkey="value" />
</x33v:repeatList>
```

In Java code, the key-based access protocol is used:

```java
// Read a value
Object value = bean.loadModelData("申込種別コード", "value");

// Write a value
bean.storeModelData("オプションサービスコード", "value", "B016");

// Write with state
bean.storeModelData("オプションサービスコード", "state", "modified");

// Add a list item
int newIndex = bean.addListDataInstance("オプションサービス契約リスト");

// Check the type
Class<?> type = bean.typeModelData("セッション数", "value");
// returns Long.class
```

## Notes for Developers

### Thread safety
The bean is **not thread-safe**. It holds mutable state (all fields are unprotected `String` and `Boolean` references, and the `X33VDataTypeList` instances are not synchronized). It is designed to be instantiated per-request or per-session in a single-threaded servlet context. Never share a single instance across multiple threads.

### Key string sensitivity
All key strings are compared using `.equals()` against **Japanese-language labels** (e.g., `"申込種別コード"`, `"オプションサービスコード"`). These are the display labels used in the UI, not the Java field names (e.g., `mskm_sbt_cd`). If you need to reference a field programmatically, use the Japanese label, not the camelCase field name.

### Subkey conventions
- `"value"` — the field's data value.
- `"state"` — the field's state/condition flag.
- `"enable"` — for fields that have a corresponding `_enabled` Boolean field (currently `session_cnt`, `use_staymd_year`, `use_staymd_mon`, `use_staymd_day`).

### List initialization
`cust_kei_hktgi_list_list` starts with one element (index 0) pre-created by the constructor. `op_svc_kei_list_list` starts empty. If you iterate over `cust_kei_hktgi_list_list` without checking, you will always find at least one element. For `op_svc_kei_list_list`, you must check `size() > 0` before accessing.

### The `_update` suffix pattern
Every scalar field has a companion `_update` field (e.g., `mskm_sbt_cd_update`). The bean provides getters and setters for these, but `loadModelData` / `storeModelData` do **not** route to them — they only route to `_value` and `_state`. The `_update` fields appear to serve a different purpose (possibly request-level change detection) and are accessed directly via their own getters/setters, not through the key-based protocol.

### Unicode minus sign normalization
The `session_cnt` field's `value` subkey performs a character substitution: `−` (Unicode en-dash, U+2212) is replaced with ASCII `'-'`. This means the stored value may differ from what `loadModelData` returns. Be aware of this when comparing values or performing equality checks.

### The `gamenId` parameter is unused
Both `loadModelData(gamenId, key, subkey)` and `storeModelData(gamenId, key, subkey, in_value)` accept a `gamenId` (screen ID) parameter but immediately delegate to the 2-argument versions that ignore it. This parameter is reserved for future use and can be safely ignored.

### `typeModelData` completeness
Every scalar field is accounted for in `typeModelData`. If a new field is added, it must be mirrored in all three routing methods (`loadModelData`, `storeModelData`, `typeModelData`) — they are maintained in lockstep and any mismatch will cause silent failures where reads return `null` or type introspection fails.

### `listServiceFormIds()` returns `null`
This method is implemented as a no-op. If the framework expects it to return a non-null array, this could cause `NullPointerException` in calling code that iterates over the result without null-checking.

### Error handling in list operations
`addListDataInstance` for `顧客契約引継リスト` enforces a maximum element count. If exceeded, it throws `super.createExceptionForX31Method(ERRS_CANNOT_ADD_REPEATITEM)`. The exact error constant `ERRS_CANNOT_ADD_REPEATITEM` and the max count value are inherited from the base class or defined in the `X33VDataTypeList` instance. Callers should catch `X33SException`.
