--------------------------------------------------------------------------------
Q1. What is a PeopleSoft Component Interface (CI), and how does it differ from
direct SQL manipulation?
--------------------------------------------------------------------------------
ANSWER:
A PeopleSoft Component Interface (CI) is a PeopleTools object that provides
programmatic access to a PeopleSoft component (page) using the same business
logic, validations, and PeopleCode events that run when a user interacts with
the component online. It acts as a wrapper around the component, exposing its
fields, keys, and methods to external programs, batch processes, or integration
points.
Key Characteristics:
- Mimics online component behavior programmatically
- Executes all PeopleCode events (FieldChange, RowInsert, SaveEdit, etc.)
- Respects buffer structure (scroll levels)
- Maintains data integrity via built-in validations
- Can be called from AE, external Java programs, or web services
Difference from Direct SQL:
CI Approach | Direct SQL Approach
------------------------------------|--------------------------------------
Triggers PeopleCode events | Bypasses all PeopleCode
Respects business rules | No business rule enforcement
Slower (event overhead) | Faster (direct DB writes)
Audit trail maintained | No automatic audit trail
Correct for business data | Risk of corrupt data
Uses Component buffer | Direct table access
Recommended for data integrity | Used only for reference/config data
REAL-TIME SCENARIO:
Project: Oracle HCM to PeopleSoft HCM migration
- Team initially used SQL inserts to load employee personal data
- Result: Missing audit rows, broken effective-dated sequences,
workflow notifications not triggered
- Switched to CI-based loading
- All PeopleCode validations executed, Workforce Administration rules applied,
workflow triggered correctly
COMMON MISTAKES:
- Using SQL inserts for transactional data that has PeopleCode business rules
- Thinking CI is always slower without considering data integrity costs
- Not understanding that CI fires SaveEdit, SavePreChange, SavePostChange events
BEST PRACTICES:
- Use CI for any transactional data load where business rules must execute
- Use SQL only for reference/lookup data loads with no business logic
- Always prototype with a small dataset before bulk loading
INTERVIEW TIP:
Emphasize that CI is not just a convenience -- it is the only correct approach
for loading data that has associated business logic, workflows, or audit trails.
FOLLOW-UP QUESTIONS:
- When would you choose direct SQL over CI?
- How does CI handle effective-dated records?
- What happens if SaveEdit PeopleCode fails during CI execution?
--------------------------------------------------------------------------------
Q2. Explain the CI object structure in detail. What are its key components?
--------------------------------------------------------------------------------
ANSWER:
The CI object structure mirrors the underlying component buffer hierarchy.
It consists of:
1. SESSION OBJECT
- Root entry point for any CI operation
- Created using %Session (in PeopleCode) or GetSession() (Java API)
- Controls mode (interactive/non-interactive), error behavior
2. COMPONENT INTERFACE OBJECT
- Obtained via Session.GetCompIntfc("CI_NAME")
- Has GetKeys, FindKeys, CreateKeys, properties, collections, methods
3. KEYS
- GetKeys: Keys used to retrieve an existing record (Get operation)
- FindKeys: Keys used to search for records (Find operation)
- CreateKeys: Keys used to create a new record (Create operation)
- Example: For JOB component, GetKey = EMPLID + EMPL_RCD
4. PROPERTIES
- Correspond to fields in the component
- Level-0 fields appear as direct properties on the CI object
- Example: CI.PERSONAL_DATA.NAME, CI.JOB.DEPTID
5. COLLECTIONS
- Correspond to scroll levels (Level 1, 2, 3 in the component)
- Accessed using array-style indexing: Collection.Item(index) [1-based]
- Example: CI.JOBCollection.Item(1).EFFDT
6. STANDARD METHODS
- Get() : Retrieve an existing record using GetKeys
- Create() : Initialize a new record
- Find() : Search using FindKeys, returns a rowset of matches
- Save() : Save the current transaction
- Cancel() : Discard changes
7. USER-DEFINED METHODS
- Custom PeopleCode methods exposed on the CI
- Defined in the component PeopleCode (CI Definition tab)
CI HIERARCHY DIAGRAM:
Session
+-- Component Interface Object (CI)
+-- GetKeys (EMPLID, EMPL_RCD)
+-- FindKeys (EMPLID)
+-- CreateKeys (BUSINESS_UNIT, JOURNAL_ID)
+-- Properties (Level-0 fields)
| +-- CI.SETID
| +-- CI.EFFDT
+-- Collections (Scroll Levels)
+-- Collection (Level-1)
| +-- Properties
| +-- Sub-Collection (Level-2)
| +-- Properties
+-- Item(1).FIELD_NAME
REAL-TIME SCENARIO:
Working on a custom benefits enrollment CI for Open Enrollment:
- Session created in AE
- CI = Session.GetCompIntfc("CI_BEN_ENROLL")
- GetKey1 = EMPLID
- GetKey2 = BENEFIT_PROGRAM
- Level-1 Collection = BenefitCollection (plan elections)
- Level-2 Sub-collection = DependentCollection (per plan)
- Save() triggered all enrollment workflow notifications
COMMON MISTAKES:
- Confusing GetKeys with FindKeys (GetKeys require exact values)
- Forgetting that collections are 1-based indexed (not 0-based)
- Not checking if a property is exposed in CI definition
BEST PRACTICES:
- Always document the key structure of each CI you build
- Validate exposed properties match what the integration partner needs
- Keep CI collections shallow -- deep nesting causes performance issues
INTERVIEW TIP:
Draw the CI hierarchy on a whiteboard if asked. Show:
Session -> CI Object -> Keys -> Properties -> Collections.
This demonstrates architectural clarity.
FOLLOW-UP QUESTIONS:
- How many scroll levels can a CI support?
- What is the difference between a Collection and a Property?
- How do you add a new row to a collection?
--------------------------------------------------------------------------------
Q3. What are GetKeys, FindKeys, and CreateKeys? When is each used?
--------------------------------------------------------------------------------
ANSWER:
These three key types serve distinct purposes in CI operations:
GETKEYS:
- Purpose: Uniquely identify an existing record to retrieve it
- Operation: Used with the Get() method
- Requirement: All GetKeys must be populated before calling Get()
- Behavior: Returns False if record not found
- Example: For CI_JOB -- EMPLID and EMPL_RCD are GetKeys
PeopleCode Example:
&oCI.EMPLID = "EMP0001";
&oCI.EMPL_RCD = 0;
If &oCI.Get() Then
/* Record loaded */
Else
/* Record not found */
End-If;
FINDKEYS:
- Purpose: Search for records matching partial criteria
- Operation: Used with the Find() method
- Returns: A rowset-like collection of matching records
- Example: Search by EMPLID only to get all job records for that employee
PeopleCode Example:
&oCI.EMPLID = "EMP0001";
&oCollection = &oCI.Find();
For &i = 1 To &oCollection.Count
/* Process each matching record */
End-For;
CREATEKEYS:
- Purpose: Define keys for creating a new record
- Operation: Used with the Create() method
- Behavior: Initializes the component buffer for a new record
- Example: For vouchers -- BUSINESS_UNIT and VOUCHER_ID are CreateKeys
PeopleCode Example:
&oCI.BUSINESS_UNIT = "US001";
&oCI.VOUCHER_ID = "NEXT";
&oCI.Create();
/* Now populate other fields */
KEY COMPARISON TABLE:
Key Type | Method | Returns | Requires Exact Values?
-----------|---------|----------------------|------------------------
GetKeys | Get() | Single record | Yes
FindKeys | Find() | Collection of rows | No (partial OK)
CreateKeys | Create()| Empty new buffer | Depends on autonumber
REAL-TIME SCENARIO:
Supplier onboarding integration:
- CreateKeys: SETID + VENDOR_ID (NEXT for auto-generated)
- Create() called to initialize new vendor record
- Properties set for vendor name, address, payment terms
- Save() called -- system auto-generated VENDOR_ID returned
- FindKeys used in reconciliation job to search vendors by NAME
COMMON MISTAKES:
- Calling Get() without setting all GetKeys -- causes runtime error
- Using GetKeys when you should use FindKeys (bulk searches)
- Not handling the case where Get() returns False
BEST PRACTICES:
- Always validate GetKey values before calling Get()
- Handle Get() = False explicitly with meaningful error messages
- Use FindKeys for validation/lookup; GetKeys for actual processing
INTERVIEW TIP:
Be ready to write code for all three scenarios. Interviewers often ask:
"Show me how you'd retrieve an employee's job record using CI."
FOLLOW-UP QUESTIONS:
- What happens if Get() fails? How do you handle it?
- Can you use Find() with no keys set? What happens?
- How are CreateKeys different for components with auto-numbered keys?
--------------------------------------------------------------------------------
Q4. Explain Collections in Component Interface. How do you navigate and
manipulate multi-level scroll data?
--------------------------------------------------------------------------------
ANSWER:
Collections in CI represent scroll level data (Level 1, 2, 3) in the component
buffer. Each collection maps to a child record/scroll in the component.
COLLECTION BASICS:
- A Collection is an array of CI row objects
- Accessed via: CI.CollectionName.Item(index) [1-based index]
- Count property: CI.CollectionName.Count
- Each item has its own properties and sub-collections
COLLECTION OPERATIONS:
1. READING EXISTING DATA:
Local ApiObject &oCI, &oJobColl, &oJobRow;
&oCI = &oSession.GetCompIntfc("CI_JOB");
&oCI.EMPLID = "EMP0001";
&oCI.EMPL_RCD = 0;
If &oCI.Get() Then
&oJobColl = &oCI.JOBCollection;
For &i = 1 To &oJobColl.Count
&oJobRow = &oJobColl.Item(&i);
MessageBox(0, "", 0, 0, "DEPTID: " | &oJobRow.DEPTID);
End-For;
End-If;
2. INSERTING A NEW ROW:
&oNewRow = &oJobColl.InsertItem(&oJobColl.Count + 1);
&oNewRow.EFFDT = %Date;
&oNewRow.EFFSEQ = 0;
&oNewRow.ACTION = "PAY";
&oNewRow.DEPTID = "DEPT001";
&oCI.Save();
3. DELETING A ROW:
&oJobColl.DeleteItem(2); /* Delete the 2nd row */
4. MULTI-LEVEL (LEVEL-2) NAVIGATION:
Local ApiObject &oL1, &oL1Row, &oL2, &oL2Row;
&oL1 = &oCI.BenefitProgramCollection;
For &i = 1 To &oL1.Count
&oL1Row = &oL1.Item(&i);
&oL2 = &oL1Row.BenefitPlanCollection;
For &j = 1 To &oL2.Count
&oL2Row = &oL2.Item(&j);
/* Process level-2 data */
End-For;
End-For;
REAL-TIME SCENARIO:
Payroll deduction interface for benefits third-party provider:
- Level-0: Employee header (EMPLID, BENEFIT_PROGRAM)
- Level-1: Each benefit plan enrollment (PLAN_TYPE, BENEFIT_PLAN)
- Level-2: Each dependent covered under that plan
- InsertItem used to add new benefit elections from external file
- DeleteItem used to remove terminated coverages
COLLECTION COUNT vs ITEM INDEX:
- Count returns total rows in the collection
- Item(1) is the first row [1-based, NOT 0-based]
- Item(Count) is the last row
- InsertItem(Count + 1) appends a new row at end
COMMON MISTAKES:
- Using 0-based indexing (Item(0) causes runtime error)
- Not checking Count before looping (empty collection has Count = 0)
- Forgetting that InsertItem fires RowInsert PeopleCode
- Modifying collection while iterating
BEST PRACTICES:
- Always check collection.Count > 0 before iterating
- Use InsertItem rather than direct row creation
- Log both the row index and key fields when errors occur
INTERVIEW TIP:
Draw Level-0 -> Level-1 -> Level-2 hierarchy and explain navigation.
Mention that InsertItem fires PeopleCode events -- this often surprises candidates.
FOLLOW-UP QUESTIONS:
- What happens to PeopleCode events when you call InsertItem?
- How do you handle a required Level-1 row when creating a new record?
- What is the maximum number of scroll levels in a CI?
--------------------------------------------------------------------------------
Q5. What are Standard Methods vs User-Defined Methods in CI?
How do you expose a custom method?
--------------------------------------------------------------------------------
ANSWER:
STANDARD METHODS (Built-in):
Method | Purpose
------------|-----------------------------------------------
Get() | Load existing record using GetKeys
Create() | Initialize a new record using CreateKeys
Find() | Search using FindKeys, return match collection
Save() | Save current record to database
Cancel() | Discard changes, reset CI state
GetPropertyByName() | Retrieve property value dynamically
USER-DEFINED METHODS:
- Custom PeopleCode functions exposed as CI methods
- Defined in Application Designer -> Component Interface -> Methods tab
- Useful for exposing complex business logic as a single callable operation
HOW TO EXPOSE A CUSTOM METHOD:
Step 1: Write PeopleCode function in component record FieldFormula
or Application Class:
Function CalculateProration(&StartDate As date, &EndDate As date)
Returns number
/* Business logic */
Return &ProratedAmount;
End-Function;
Step 2: In Application Designer, open the CI definition
Step 3: Go to Methods tab
Step 4: Add method name and map to PeopleCode function
Step 5: Save and build
CALLING A USER-DEFINED METHOD:
Local ApiObject &oCI;
&oCI = &oSession.GetCompIntfc("CI_PAYROLL");
&oCI.EMPLID = "EMP001";
&oCI.Get();
Local number &Amount;
&Amount = &oCI.CalculateProration(%Date - 30, %Date);
REAL-TIME SCENARIO:
Global Payroll implementation:
- CI exposed with standard Get/Save for payroll element entry
- User-defined method "ValidatePayElement" exposed on CI
- Third-party payroll engine called this method before submitting data
- Method internally ran complex eligibility rules in PeopleCode
- Returned True/False with error message
COMMON MISTAKES:
- Trying to expose methods that use interactive functions (DoModal, etc.)
- Not testing user-defined methods in non-interactive mode
- Forgetting to add the method to the Permission List
BEST PRACTICES:
- Keep user-defined CI methods stateless and side-effect free
- Document input/output parameters clearly
- Test in both AE context and Java API context
INTERVIEW TIP:
Explain that user-defined methods are like a "service layer" on top of CI --
they let you expose atomic business operations to external systems cleanly.
FOLLOW-UP QUESTIONS:
- Can a user-defined CI method call other CIs internally?
- How do you pass complex data structures to a CI method?
- What limitations exist for user-defined CI methods?
--------------------------------------------------------------------------------
Q6. Explain Interactive Mode vs Non-Interactive Mode in Component Interface.
--------------------------------------------------------------------------------
ANSWER:
INTERACTIVE MODE:
- Used when the calling program can interact with pop-up dialogs
- Supports DoModal, transfer functions, WinMessage
- Session connected to an active user session with browser context
- Less common in integration scenarios
NON-INTERACTIVE MODE:
- Designed for batch/automated processing (Application Engine, Java API)
- No user interaction -- all prompts and dialogs suppressed
- Error messages captured in error collection, not displayed as pop-ups
- Standard mode for CI-based data integration
SETTING NON-INTERACTIVE MODE (Java API):
PeopleSoftSession session = new PeopleSoftSession();
session.connect(1, "SERVER_NAME", "PEOPLESOFT", "PS", "PS");
session.setInteractiveMode(false);
CompIntfc ci = session.getCompIntfc("CI_PERSONAL_DATA");
IN PEOPLECODE (Application Engine):
/* %Session in AE is already non-interactive by default */
Local ApiObject &oSession;
&oSession = %Session;
KEY BEHAVIORAL DIFFERENCES:
Feature | Interactive | Non-Interactive
-----------------------|-------------------|------------------
Pop-up dialogs | Displayed | Suppressed
Error handling | User sees errors | Error collection
PeopleCode events | All fire | All fire
Batch processing | Not suitable | Designed for this
Session origin | Browser session | API session
Performance | Lower | Higher throughput
NON-INTERACTIVE ERROR HANDLING:
If Not &oCI.Save() Then
Local ApiObject &oErrors;
&oErrors = &oCI.GetErrors();
For &i = 1 To &oErrors.Count
Local ApiObject &oError;
&oError = &oErrors.Item(&i);
MessageBox(0,"",0,0, "Error: " | &oError.Text |
" Field: " | &oError.Field);
End-For;
End-If;
REAL-TIME SCENARIO:
Benefits open enrollment mass update job:
- Application Engine ran in non-interactive mode
- CI loaded 15,000 employee benefit elections overnight
- All save errors captured in error collection and written to error table
- Operations team reviewed error table next morning
- Re-run logic built for failed records only
- Zero user interaction required
COMMON MISTAKES:
- Using WinMessage inside CI-called PeopleCode in non-interactive mode
- Not implementing error collection processing (silently ignoring failures)
- Expecting pop-up error messages in batch mode
BEST PRACTICES:
- Always code for non-interactive mode in batch CI programs
- Implement comprehensive error collection processing
- Write all errors to a staging error table for operations review
INTERVIEW TIP:
Mention that some PeopleCode constructs (Transfer, DoModal) are invalid in
non-interactive mode and will cause runtime errors.
FOLLOW-UP QUESTIONS:
- How does error collection work in non-interactive mode?
- What PeopleCode functions are not allowed in non-interactive mode?
- How do you test a CI in non-interactive mode during development?
--------------------------------------------------------------------------------
Q7. How does the CI Session Object work? What are its key methods and properties?
--------------------------------------------------------------------------------
ANSWER:
The Session Object is the root of all CI operations. It represents a connection
to PeopleSoft and provides the gateway to all Component Interface objects.
OBTAINING THE SESSION OBJECT:
In PeopleCode (within PeopleSoft):
Local ApiObject &oSession;
&oSession = %Session;
/* %Session is the built-in session in PeopleCode context */
In Java (external application):
import PeopleSoft.PeopleTools.*;
PeopleSoftSession session = new PeopleSoftSession();
int rc = session.connect(1, "APPSERVER_NAME", "DB_NAME", "USERID", "PSWD");
SESSION OBJECT KEY METHODS:
Method | Purpose
-------------------------------|----------------------------------------
GetCompIntfc(name) | Get a CI object by name
getCompIntfc(name) | Java API equivalent
SetInteractiveMode(bool) | Toggle interactive/non-interactive
GetErrors() | Get error collection from last operation
ReturnToServer() | Disconnect (Java)
disconnect() | Java API: end session
SetAuthToken(token) | Set auth token for SSO scenarios
SESSION PROPERTIES:
Property | Description
----------------------|-------------------------------------------
PSMessages | Collection of messages/errors
LogFence | Controls trace log level
TraceFlags | Bit flags for trace output
COMPLETE SESSION WORKFLOW (PeopleCode AE):
Local ApiObject &oSession, &oCI;
&oSession = %Session;
&oCI = &oSession.GetCompIntfc("CI_PERSONAL_DATA");
If None(&oCI) Then
MessageBox(0,"",0,0,"CI not found - check name and permissions");
Exit(1);
End-If;
&oCI.EMPLID = "EMP001";
If &oCI.Get() Then
&oCI.NAME = "Smith, John";
&oCI.Save();
End-If;
SESSION IN JAVA API (External System):
PeopleSoftSession psSession = null;
try {
psSession = new PeopleSoftSession();
int rc = psSession.connect(1, "APPSVR01:9000", "HRMS91",
"PSUSER", "PSPASS");
if (rc != 0) throw new Exception("Connect failed: " + rc);
CompIntfc oCI = psSession.getCompIntfc("CI_JOB_DATA");
oCI.setInteractiveMode(false);
// ... operations ...
} finally {
if (psSession != null) psSession.disconnect();
}
REAL-TIME SCENARIO:
SAP HR to PeopleSoft position sync:
- Java middleware obtained session for each batch run
- Session reused across 500 CI calls (session pooling pattern)
- &oSession.GetErrors() checked after every Save()
- Session disconnected gracefully in finally block
- Connection failures handled with retry logic
COMMON MISTAKES:
- Not disconnecting Java sessions (causes App Server connection leaks)
- Using %Session outside of PeopleCode context
- Not checking the return code of connect() in Java
BEST PRACTICES:
- Always disconnect Java sessions in finally blocks
- Reuse sessions across multiple CI operations (performance)
- Check GetErrors() after every Save(), not just at end
INTERVIEW TIP:
Distinguish between %Session (PeopleCode built-in) and Java's
PeopleSoftSession. Interviewers value candidates who understand both contexts.
FOLLOW-UP QUESTIONS:
- How do you implement session pooling for CI?
- What is the impact of not disconnecting a Java session?
- How do you pass authentication tokens for SSO?
--------------------------------------------------------------------------------
Q8. What is the CI Object Hierarchy for a multi-scroll component?
Describe with a real example using JOB_DATA.
--------------------------------------------------------------------------------
ANSWER:
For a component with multiple scroll levels (like JOB_DATA), the CI object
hierarchy directly mirrors the page buffer structure.
REAL EXAMPLE: JOB_DATA Component Interface (CI_JOB_DATA)
Component Page Structure:
Level 0: PERSONAL_DATA (EMPLID)
Level 1: EMPLOYMENT (EMPLID, EMPL_RCD)
Level 2: JOB (EMPLID, EMPL_RCD, EFFDT, EFFSEQ)
Level 3: JOB_JR (Compensation rates)
CI Object Hierarchy:
&oCI (CI_JOB_DATA)
+-- GetKeys: EMPLID, EMPL_RCD
+-- Properties (Level-0): EMPLID, NAME, etc.
+-- EMPLOYMENTCollection (Level-1):
+-- Item(1):
+-- EMPL_RCD, EMPL_STATUS, etc.
+-- JOBCollection (Level-2):
+-- Item(n):
+-- EFFDT, ACTION, DEPTID, JOBCODE
+-- JOB_JRCollection (Level-3):
+-- Item(1):
+-- COMPRATE, CURRENCY_CD
PEOPLECODE NAVIGATION (3 levels):
Local ApiObject &oCI, &oL1, &oL2, &oL3;
Local ApiObject &oL1Row, &oL2Row, &oL3Row;
&oCI = %Session.GetCompIntfc("CI_JOB_DATA");
&oCI.EMPLID = "EMP001";
&oCI.EMPL_RCD = 0;
If &oCI.Get() Then
&oL1 = &oCI.EMPLOYMENTCollection;
For &i = 1 To &oL1.Count
&oL1Row = &oL1.Item(&i);
&oL2 = &oL1Row.JOBCollection;
For &j = 1 To &oL2.Count
&oL2Row = &oL2.Item(&j);
MessageBox(0,"",0,0,"Action: " | &oL2Row.ACTION);
&oL3 = &oL2Row.JOB_JRCollection;
For &k = 1 To &oL3.Count
&oL3Row = &oL3.Item(&k);
MessageBox(0,"",0,0,"Rate: " | &oL3Row.COMPRATE);
End-For;
End-For;
End-For;
End-If;
REAL-TIME SCENARIO:
Compensation review mass update:
- CI_JOB_DATA used to update compensation rates during merit cycle
- Navigate to Level-2 (JOB) to find current active row
- Insert new Level-2 row with ACTION = "PAY", new EFFDT
- Navigate to Level-3 (JOB_JR) under new row
- InsertItem for each pay component with new COMPRATE
- Save() triggered all compensation PeopleCode validations
COMMON MISTAKES:
- Assuming Level-1 always has exactly one row (it may have multiple)
- Not setting EFFDT and EFFSEQ when inserting Level-2 rows
- Forgetting Level-3 rows must be inserted after Level-2 is created
BEST PRACTICES:
- Always traverse all levels methodically; never assume row counts
- Insert required Level-3 rows immediately after Level-2 creation
- Log each level's key fields when writing error messages
INTERVIEW TIP:
Walk through this example step by step. Showing you understand 3-level
navigation instantly distinguishes you from average candidates.
FOLLOW-UP QUESTIONS:
- How do you find the most recent effective-dated row in a Level-2 collection?
- What happens if you try to insert a Level-3 row without a Level-2 parent?
- How does a 3-level CI perform vs a 2-level CI for bulk loading?
No comments:
Post a Comment