After establishing your foundation in z/OS, COBOL, and basic messaging, it’s time to dive deep into the heart of mainframe modernization: database integration with DB2modern tooling with IBM z/OS Connect and Zowe, and hands-on API creation. This phase transforms you from understanding mainframe basics to actively building modern interfaces that bridge legacy and cloud systems.


Week 9-10: DB2 Database Fundamentals Deep Dive

Understanding DB2 Architecture and Database Objects

Day 64-66: DB2 System Architecture and Hierarchy

Step 22: DB2 System Structure Mastery

  • Micro-step 22.1: Learn the complete DB2 hierarchy
    • Storage Groups: Top-level containers that define physical storage devices
    • Databases: Logical groupings of related objects within storage groups
    • Table Spaces: Containers for tables, providing physical storage allocation
    • Index Spaces: Separate containers for indexes that point to table data
    • Tables: The actual data structures containing rows and columns
    • Indexes: Ordered pointers for performance and uniqueness enforcement
  • Micro-step 22.2: Understand DB2 subsystem concepts
    • DB2 Subsystem Naming: Convention like DS01 (Development), TS01 (Test), PS01 (Production)
    • Multiple Subsystems: How different environments share table structures but maintain separate data
    • Subsystem Communication: Inter-system data sharing and replication patterns

Practical Exercise 9.1: Explore DB2 system catalog:

sql-- Connect to DB2 subsystem
DB2 
-- Display current subsystem information
DISPLAY GROUP
-- Show database structure
SELECT * FROM SYSIBM.SYSDATABASE WHERE NAME LIKE 'DSN%';
-- List table spaces
SELECT DBNAME, NAME, TYPE, STATUS 
FROM SYSIBM.SYSTABLESPACE 
WHERE DBNAME = 'DSNDB04';

Day 67-70: Advanced DB2 Database Design

Step 23: Schema Design for Modernization

  • Micro-step 23.1: Master schema concepts for API enablement
    • Schema Separation: Create logical boundaries using different schemas (CUSTOMER_API, PRODUCT_API)
    • Naming Conventions: Establish consistent patterns for modernization projects
    • Authorization Management: Control access at schema level for API security
    • Version Management: Handle schema evolution for API backward compatibility

Practical Exercise 9.2: Create modernization-ready schemas:

sql-- Create schemas for different API domains
CREATE SCHEMA CUSTOMER_API AUTHORIZATION DB2ADMIN;
CREATE SCHEMA PRODUCT_API AUTHORIZATION DB2ADMIN;
CREATE SCHEMA TRANSACTION_API AUTHORIZATION DB2ADMIN;

-- Set working schema
SET SCHEMA = CUSTOMER_API;

-- Create tables with API-friendly structure
CREATE TABLE CUSTOMERS (
    CUSTOMER_ID         CHAR(10) NOT NULL PRIMARY KEY,
    CUSTOMER_TYPE       CHAR(1) NOT NULL CHECK (CUSTOMER_TYPE IN ('I','C')),
    FIRST_NAME          VARCHAR(50),
    LAST_NAME           VARCHAR(50) NOT NULL,
    EMAIL_ADDRESS       VARCHAR(100),
    PHONE_NUMBER        VARCHAR(20),
    DATE_CREATED        TIMESTAMP NOT NULL DEFAULT CURRENT TIMESTAMP,
    DATE_MODIFIED       TIMESTAMP NOT NULL DEFAULT CURRENT TIMESTAMP,
    STATUS              CHAR(1) NOT NULL DEFAULT 'A' CHECK (STATUS IN ('A','I','S')),
    VERSION_NUMBER      INTEGER NOT NULL DEFAULT 1
);

-- Create address table with proper relationships
CREATE TABLE CUSTOMER_ADDRESSES (
    ADDRESS_ID          INTEGER NOT NULL PRIMARY KEY,
    CUSTOMER_ID         CHAR(10) NOT NULL,
    ADDRESS_TYPE        CHAR(1) NOT NULL CHECK (ADDRESS_TYPE IN ('H','W','M')),
    STREET_ADDRESS_1    VARCHAR(100),
    STREET_ADDRESS_2    VARCHAR(100),
    CITY                VARCHAR(50),
    STATE_PROVINCE      VARCHAR(50),
    POSTAL_CODE         VARCHAR(20),
    COUNTRY_CODE        CHAR(2) DEFAULT 'US',
    IS_PRIMARY          CHAR(1) DEFAULT 'N' CHECK (IS_PRIMARY IN ('Y','N')),
    DATE_CREATED        TIMESTAMP NOT NULL DEFAULT CURRENT TIMESTAMP,
    FOREIGN KEY (CUSTOMER_ID) REFERENCES CUSTOMERS(CUSTOMER_ID)
);

-- Create indexes for API performance
CREATE UNIQUE INDEX IX_CUSTOMER_EMAIL ON CUSTOMERS(EMAIL_ADDRESS);
CREATE INDEX IX_CUSTOMER_TYPE_STATUS ON CUSTOMERS(CUSTOMER_TYPE, STATUS);
CREATE INDEX IX_ADDRESS_CUSTOMER ON CUSTOMER_ADDRESSES(CUSTOMER_ID);

Advanced SQL Operations for API Development

Day 71-73: Complex Queries and JSON Integration

Step 24: SQL Optimization for API Performance

  • Micro-step 24.1: Master advanced SQL patterns for APIs
    • JOIN Optimization: Efficient multi-table queries for comprehensive API responses
    • Subqueries vs CTEs: When to use Common Table Expressions for readability
    • Window Functions: Advanced analytics for API data aggregation
    • Pagination Techniques: OFFSET/FETCH for large result sets in APIs
  • Micro-step 24.2: JSON and XML handling in DB2
    • JSON_OBJECT function: Creating JSON responses directly from SQL
    • JSON_ARRAY function: Handling collections in API responses
    • XML processing: Legacy XML integration patterns

Practical Exercise 9.3: Build API-ready queries:

sql-- Complex customer data retrieval for API
WITH CUSTOMER_SUMMARY AS (
    SELECT 
        c.CUSTOMER_ID,
        c.FIRST_NAME,
        c.LAST_NAME,
        c.EMAIL_ADDRESS,
        c.PHONE_NUMBER,
        c.STATUS,
        c.DATE_CREATED,
        COUNT(a.ADDRESS_ID) as ADDRESS_COUNT
    FROM CUSTOMER_API.CUSTOMERS c
    LEFT JOIN CUSTOMER_API.CUSTOMER_ADDRESSES a 
        ON c.CUSTOMER_ID = a.CUSTOMER_ID
    GROUP BY c.CUSTOMER_ID, c.FIRST_NAME, c.LAST_NAME, 
             c.EMAIL_ADDRESS, c.PHONE_NUMBER, c.STATUS, c.DATE_CREATED
),
RECENT_CUSTOMERS AS (
    SELECT *,
           ROW_NUMBER() OVER (ORDER BY DATE_CREATED DESC) as RN
    FROM CUSTOMER_SUMMARY
)
SELECT 
    JSON_OBJECT(
        'customerId' VALUE CUSTOMER_ID,
        'name' VALUE JSON_OBJECT(
            'firstName' VALUE FIRST_NAME,
            'lastName' VALUE LAST_NAME
        ),
        'contactInfo' VALUE JSON_OBJECT(
            'email' VALUE EMAIL_ADDRESS,
            'phone' VALUE PHONE_NUMBER
        ),
        'metadata' VALUE JSON_OBJECT(
            'status' VALUE STATUS,
            'addressCount' VALUE ADDRESS_COUNT,
            'dateCreated' VALUE DATE_CREATED
        )
    ) as CUSTOMER_JSON
FROM RECENT_CUSTOMERS
WHERE RN <= 50;  -- Pagination: First 50 records

-- Stored procedure for customer CRUD operations
CREATE PROCEDURE CUSTOMER_API.GET_CUSTOMER_DETAILS(
    IN P_CUSTOMER_ID CHAR(10),
    OUT P_RESULT_JSON CLOB(32K)
)
LANGUAGE SQL
BEGIN
    DECLARE SQLSTATE CHAR(5) DEFAULT '00000';
    DECLARE v_count INTEGER DEFAULT 0;
    
    -- Check if customer exists
    SELECT COUNT(*) INTO v_count
    FROM CUSTOMER_API.CUSTOMERS
    WHERE CUSTOMER_ID = P_CUSTOMER_ID;
    
    IF v_count = 0 THEN
        SET P_RESULT_JSON = JSON_OBJECT(
            'error' VALUE 'Customer not found',
            'customerId' VALUE P_CUSTOMER_ID
        );
    ELSE
        -- Build comprehensive customer JSON
        SELECT JSON_OBJECT(
            'customer' VALUE JSON_OBJECT(
                'customerId' VALUE c.CUSTOMER_ID,
                'name' VALUE JSON_OBJECT(
                    'firstName' VALUE c.FIRST_NAME,
                    'lastName' VALUE c.LAST_NAME
                ),
                'contactInfo' VALUE JSON_OBJECT(
                    'email' VALUE c.EMAIL_ADDRESS,
                    'phone' VALUE c.PHONE_NUMBER
                ),
                'addresses' VALUE JSON_ARRAY(
                    SELECT JSON_OBJECT(
                        'addressId' VALUE a.ADDRESS_ID,
                        'type' VALUE a.ADDRESS_TYPE,
                        'street1' VALUE a.STREET_ADDRESS_1,
                        'street2' VALUE a.STREET_ADDRESS_2,
                        'city' VALUE a.CITY,
                        'state' VALUE a.STATE_PROVINCE,
                        'postalCode' VALUE a.POSTAL_CODE,
                        'country' VALUE a.COUNTRY_CODE,
                        'isPrimary' VALUE a.IS_PRIMARY
                    )
                    FROM CUSTOMER_API.CUSTOMER_ADDRESSES a
                    WHERE a.CUSTOMER_ID = c.CUSTOMER_ID
                )
            )
        ) INTO P_RESULT_JSON
        FROM CUSTOMER_API.CUSTOMERS c
        WHERE c.CUSTOMER_ID = P_CUSTOMER_ID;
    END IF;
END;

Day 74-77: Performance Tuning and Monitoring

Step 25: DB2 Performance Optimization for APIs

  • Micro-step 25.1: Index strategy for API workloads
    • Covering Indexes: Include all needed columns to avoid table lookups
    • Composite Indexes: Multi-column indexes for complex WHERE clauses
    • Index Monitoring: Using DB2 statistics to optimize performance
  • Micro-step 25.2: Connection pooling and resource management
    • Connection Pooling: Managing DB2 connections for high-volume APIs
    • Transaction Management: Short-lived transactions for API responsiveness
    • Lock Management: Avoiding deadlocks in concurrent API operations

Practical Exercise 9.4: Performance monitoring setup:

sql-- Create performance monitoring tables
CREATE TABLE CUSTOMER_API.API_PERFORMANCE_LOG (
    LOG_ID              INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    API_ENDPOINT        VARCHAR(100) NOT NULL,
    CUSTOMER_ID         CHAR(10),
    START_TIME          TIMESTAMP NOT NULL,
    END_TIME            TIMESTAMP,
    RESPONSE_TIME_MS    INTEGER,
    RECORD_COUNT        INTEGER,
    STATUS_CODE         INTEGER,
    ERROR_MESSAGE       VARCHAR(500),
    SQL_STATEMENTS      CLOB(10K)
);

-- Performance monitoring stored procedure
CREATE PROCEDURE CUSTOMER_API.LOG_API_PERFORMANCE(
    IN P_ENDPOINT VARCHAR(100),
    IN P_CUSTOMER_ID CHAR(10),
    IN P_START_TIME TIMESTAMP,
    IN P_END_TIME TIMESTAMP,
    IN P_RECORD_COUNT INTEGER,
    IN P_STATUS_CODE INTEGER,
    IN P_ERROR_MESSAGE VARCHAR(500)
)
LANGUAGE SQL
BEGIN
    DECLARE v_response_time INTEGER;
    
    SET v_response_time = 
        INTEGER(MICROSECOND(P_END_TIME - P_START_TIME) / 1000);
    
    INSERT INTO CUSTOMER_API.API_PERFORMANCE_LOG (
        API_ENDPOINT, CUSTOMER_ID, START_TIME, END_TIME,
        RESPONSE_TIME_MS, RECORD_COUNT, STATUS_CODE, ERROR_MESSAGE
    ) VALUES (
        P_ENDPOINT, P_CUSTOMER_ID, P_START_TIME, P_END_TIME,
        v_response_time, P_RECORD_COUNT, P_STATUS_CODE, P_ERROR_MESSAGE
    );
END;

-- Performance analysis queries
-- Find slow API calls
SELECT API_ENDPOINT, AVG(RESPONSE_TIME_MS) as AVG_RESPONSE_TIME,
       COUNT(*) as CALL_COUNT, MAX(RESPONSE_TIME_MS) as MAX_RESPONSE_TIME
FROM CUSTOMER_API.API_PERFORMANCE_LOG
WHERE START_TIME >= CURRENT_TIMESTAMP - 1 DAY
GROUP BY API_ENDPOINT
ORDER BY AVG_RESPONSE_TIME DESC;

Week 11-12: IBM z/OS Connect Enterprise Edition Mastery

Installation and Configuration of z/OS Connect EE

Day 78-80: z/OS Connect EE Setup and Architecture

Step 26: Complete z/OS Connect EE Installation

  • Micro-step 26.1: Understand z/OS Connect EE architecture
    • Liberty Server Foundation: Java-based runtime environment
    • Service Providers: Connectors to CICS, IMS, DB2, and Batch programs
    • API Management: Request/response transformation and routing
    • Security Framework: Authentication, authorization, and audit capabilities
  • Micro-step 26.2: Installation and basic configuration
    • SMP/E Installation: Using IBM installation procedures
    • Liberty Server Setup: Creating and configuring Liberty profile
    • Port Configuration: Setting up HTTP and HTTPS listeners
    • Basic Security: SSL certificates and user authentication

Practical Exercise 10.1: Set up z/OS Connect EE environment:

xml<!-- server.xml configuration for z/OS Connect EE -->
<server description="z/OS Connect EE Server">
    <featureManager>
        <feature>zosConnect-2.0</feature>
        <feature>ssl-1.0</feature>
        <feature>appSecurity-2.0</feature>
    </featureManager>
    
    <httpEndpoint id="defaultHttpEndpoint"
                  httpPort="8080"
                  httpsPort="8443"
                  host="*" />
    
    <!-- SSL Configuration -->
    <ssl id="defaultSSLConfig"
         keyStoreRef="defaultKeyStore"
         trustStoreRef="defaultTrustStore" />
    
    <keyStore id="defaultKeyStore"
              location="key.p12"
              type="PKCS12"
              password="{aes}encrypted_password" />
    
    <!-- z/OS Connect Configuration -->
    <zosconnect_zosConnectManager 
        requireAuth="true"
        invokeTimeout="300000">
        <authConfig>
            <server>
                <basicAuth id="basicAuth"
                          userRegistryRef="basic" />
                <userRegistry id="basic"
                             realm="zOSConnectRealm">
                    <user name="zosconnect" 
                          password="{aes}encrypted_password" />
                </userRegistry>
            </server>
        </authConfig>
    </zosconnect_zosConnectManager>
    
    <!-- Application Logging -->
    <logging traceSpecification="*=info:com.ibm.zosconnect.*=all" 
             maxFileSize="20"
             maxFiles="10" />
</server>

Day 81-84: Service Provider Configuration

Step 27: Configure Service Providers for Different Subsystems

  • Micro-step 27.1: CICS Service Provider setup
    • CICS Connection: Configuring CICS Transaction Gateway or CICS TS connectivity
    • Program Mapping: Linking CICS programs to z/OS Connect services
    • Transaction Management: Handling CICS transaction boundaries
  • Micro-step 27.2: DB2 Service Provider configuration
    • DB2 Connection: JDBC configuration for DB2 z/OS
    • SQL Service Creation: Mapping SQL operations to REST services
    • Connection Pooling: Optimizing DB2 connections for high throughput

Practical Exercise 10.2: Configure multiple service providers:

xml<!-- Service Provider Configurations in server.xml -->

<!-- CICS Service Provider -->
<zosconnect_cicsServiceProvider id="cicsProvider"
    enabler="CICSTransactionGateway"
    gatewayUrl="https://cics.company.com:9080"
    userName="${cics.user}"
    password="${cics.password}"
    maxConnections="10" />

<!-- DB2 Service Provider -->
<dataSource id="db2DataSource" 
            jndiName="jdbc/DB2DataSource"
            type="javax.sql.ConnectionPoolDataSource">
    <jdbcDriver javax.sql.ConnectionPoolDataSource="com.ibm.db2.jcc.DB2ConnectionPoolDataSource"
                libraryRef="DB2JCCLib" />
    <properties.db2.jcc databaseName="DSN1"
                        serverName="db2.company.com"
                        portNumber="446"
                        user="${db2.user}"
                        password="${db2.password}" />
    <connectionManager maxPoolSize="50" 
                      minPoolSize="10"
                      connectionTimeout="30s" />
</dataSource>

<zosconnect_db2ServiceProvider id="db2Provider"
    dataSourceRef="db2DataSource" />

<!-- Batch Service Provider -->
<zosconnect_batchServiceProvider id="batchProvider"
    batchJobSubmissionStrategy="JES_JAVA_BATCH_SUBMIT" />

Creating Services from COBOL Programs

Day 85-87: Service Development Workflow

Step 28: Service Creation from Existing COBOL Programs

  • Micro-step 28.1: Analyze existing COBOL programs for service enablement
    • Program Interface Analysis: Understanding LINKAGE SECTION parameters
    • Data Structure Mapping: Converting COBOL copybooks to JSON schema
    • Error Handling Integration: Mapping COBOL return codes to HTTP status codes
  • Micro-step 28.2: Use z/OS Connect API Toolkit
    • Service Creation Wizard: Step-by-step service generation
    • Request/Response Mapping: Defining JSON to COBOL data transformation
    • Service Testing: Built-in testing capabilities

Practical Exercise 10.3: Create service from COBOL program:

COBOL Program (CUSTINQ.cbl):

textIDENTIFICATION DIVISION.
PROGRAM-ID. CUSTINQ.

DATA DIVISION.
WORKING-STORAGE SECTION.
01  WS-DB2-AREA.
    EXEC SQL INCLUDE SQLCA END-EXEC.
    EXEC SQL INCLUDE CUSTOMER END-EXEC.

LINKAGE SECTION.
01  LS-INPUT-DATA.
    05  LS-CUSTOMER-ID          PIC X(10).
    05  LS-REQUEST-TYPE         PIC X(1).
        88  INQUIRY-REQUEST     VALUE 'I'.
        88  UPDATE-REQUEST      VALUE 'U'.
    05  LS-CUSTOMER-DATA.
        10  LS-FIRST-NAME       PIC X(50).
        10  LS-LAST-NAME        PIC X(50).
        10  LS-EMAIL            PIC X(100).
        10  LS-PHONE            PIC X(20).

01  LS-OUTPUT-DATA.
    05  LS-RESPONSE-CODE        PIC 9(3).
        88  SUCCESS-RESPONSE    VALUE 200.
        88  NOT-FOUND-RESPONSE  VALUE 404.
        88  ERROR-RESPONSE      VALUE 500.
    05  LS-RESPONSE-MESSAGE     PIC X(100).
    05  LS-CUSTOMER-DETAILS.
        10  LS-OUT-CUSTOMER-ID  PIC X(10).
        10  LS-OUT-FIRST-NAME   PIC X(50).
        10  LS-OUT-LAST-NAME    PIC X(50).
        10  LS-OUT-EMAIL        PIC X(100).
        10  LS-OUT-PHONE        PIC X(20).
        10  LS-OUT-STATUS       PIC X(1).
        10  LS-OUT-DATE-CREATED PIC X(26).

PROCEDURE DIVISION USING LS-INPUT-DATA, LS-OUTPUT-DATA.
MAIN-PROCESS.
    INITIALIZE LS-OUTPUT-DATA
    
    EVALUATE TRUE
        WHEN INQUIRY-REQUEST
            PERFORM GET-CUSTOMER-DETAILS
        WHEN UPDATE-REQUEST
            PERFORM UPDATE-CUSTOMER-DETAILS
        WHEN OTHER
            MOVE 400 TO LS-RESPONSE-CODE
            MOVE 'Invalid request type' TO LS-RESPONSE-MESSAGE
    END-EVALUATE
    
    GOBACK.

GET-CUSTOMER-DETAILS.
    EXEC SQL
        SELECT CUSTOMER_ID, FIRST_NAME, LAST_NAME, EMAIL_ADDRESS,
               PHONE_NUMBER, STATUS, CHAR(DATE_CREATED)
        INTO :HOST-CUSTOMER-ID, :HOST-FIRST-NAME, :HOST-LAST-NAME,
             :HOST-EMAIL, :HOST-PHONE, :HOST-STATUS, :HOST-DATE-CREATED
        FROM CUSTOMER_API.CUSTOMERS
        WHERE CUSTOMER_ID = :LS-CUSTOMER-ID
    END-EXEC
    
    EVALUATE SQLCODE
        WHEN 0
            MOVE 200 TO LS-RESPONSE-CODE
            MOVE 'Customer found' TO LS-RESPONSE-MESSAGE
            MOVE HOST-CUSTOMER-ID TO LS-OUT-CUSTOMER-ID
            MOVE HOST-FIRST-NAME TO LS-OUT-FIRST-NAME
            MOVE HOST-LAST-NAME TO LS-OUT-LAST-NAME
            MOVE HOST-EMAIL TO LS-OUT-EMAIL
            MOVE HOST-PHONE TO LS-OUT-PHONE
            MOVE HOST-STATUS TO LS-OUT-STATUS
            MOVE HOST-DATE-CREATED TO LS-OUT-DATE-CREATED
        WHEN 100
            MOVE 404 TO LS-RESPONSE-CODE
            MOVE 'Customer not found' TO LS-RESPONSE-MESSAGE
        WHEN OTHER
            MOVE 500 TO LS-RESPONSE-CODE
            MOVE 'Database error occurred' TO LS-RESPONSE-MESSAGE
    END-EVALUATE.

Service Configuration (customer-inquiry-service.json):

json{
  "serviceName": "customerInquiry",
  "serviceDescription": "Customer inquiry and update service",
  "serviceProvider": "cicsProvider",
  "program": "CUSTINQ",
  "requestSchema": {
    "$schema": "http://json-schema.org/draft-04/schema#",
    "type": "object",
    "properties": {
      "customerId": {
        "type": "string",
        "maxLength": 10
      },
      "requestType": {
        "type": "string",
        "enum": ["I", "U"]
      },
      "customerData": {
        "type": "object",
        "properties": {
          "firstName": {"type": "string", "maxLength": 50},
          "lastName": {"type": "string", "maxLength": 50},
          "email": {"type": "string", "maxLength": 100},
          "phone": {"type": "string", "maxLength": 20}
        }
      }
    },
    "required": ["customerId", "requestType"]
  },
  "responseSchema": {
    "$schema": "http://json-schema.org/draft-04/schema#",
    "type": "object",
    "properties": {
      "responseCode": {"type": "integer"},
      "responseMessage": {"type": "string"},
      "customerDetails": {
        "type": "object",
        "properties": {
          "customerId": {"type": "string"},
          "firstName": {"type": "string"},
          "lastName": {"type": "string"},
          "email": {"type": "string"},
          "phone": {"type": "string"},
          "status": {"type": "string"},
          "dateCreated": {"type": "string"}
        }
      }
    }
  }
}

Day 88-91: Advanced Service Features

Step 29: Implement Advanced Service Capabilities

  • Micro-step 29.1: Error handling and status management
    • HTTP Status Code Mapping: Converting COBOL return codes to proper HTTP statuses
    • Error Response Formatting: Consistent error message structures
    • Logging and Auditing: Comprehensive request/response logging
  • Micro-step 29.2: Service versioning and lifecycle management
    • API Versioning: Managing multiple versions of the same service
    • Backward Compatibility: Ensuring existing consumers continue to work
    • Service Deployment: Blue-green deployment strategies

Practical Exercise 10.4: Build comprehensive service management:

javascript// Service interceptor for logging and error handling
function preInvoke(serviceContext) {
    var requestId = generateRequestId();
    serviceContext.setProperty("requestId", requestId);
    serviceContext.setProperty("startTime", new Date().getTime());
    
    // Log incoming request
    logger.info("Request " + requestId + " - Service: " + 
               serviceContext.getServiceName() + 
               " - Input: " + JSON.stringify(serviceContext.getRequestJSON()));
    
    // Validate input
    var validation = validateRequest(serviceContext.getRequestJSON());
    if (!validation.valid) {
        throw new ServiceException(400, validation.message);
    }
}

function postInvoke(serviceContext) {
    var requestId = serviceContext.getProperty("requestId");
    var startTime = serviceContext.getProperty("startTime");
    var endTime = new Date().getTime();
    var duration = endTime - startTime;
    
    // Log response
    logger.info("Response " + requestId + " - Duration: " + duration + "ms" +
               " - Output: " + JSON.stringify(serviceContext.getResponseJSON()));
    
    // Add response headers
    serviceContext.setResponseHeader("X-Request-ID", requestId);
    serviceContext.setResponseHeader("X-Response-Time", duration + "ms");
}

function validateRequest(requestJson) {
    if (!requestJson.customerId || requestJson.customerId.trim() === "") {
        return {valid: false, message: "Customer ID is required"};
    }
    
    if (requestJson.customerId.length > 10) {
        return {valid: false, message: "Customer ID must be 10 characters or less"};
    }
    
    if (!requestJson.requestType || 
        (requestJson.requestType !== "I" && requestJson.requestType !== "U")) {
        return {valid: false, message: "Request type must be 'I' or 'U'"};
    }
    
    return {valid: true};
}

Week 13-14: Zowe CLI and API Mediation Layer

Setting Up Zowe Development Environment

Day 92-94: Zowe Installation and Configuration

Step 30: Complete Zowe Environment Setup

  • Micro-step 30.1: Zowe server-side installation
    • Zowe Runtime: Installing Zowe on z/OS system
    • API Mediation Layer: Gateway configuration and setup
    • Security Configuration: Certificate management and SSO setup
    • High Availability: Multi-instance configuration for production
  • Micro-step 30.2: Zowe CLI installation and profile setup
    • CLI Installation: npm installation and global configuration
    • Profile Creation: Connecting to multiple z/OS systems
    • Plugin Management: Installing and configuring extensions

Practical Exercise 11.1: Set up complete Zowe environment:

bash# Install Zowe CLI
npm install -g @zowe/cli@zowe-v2-lts

# Verify installation
zowe --version

# Create profiles for different environments
zowe profiles create zosmf-profile dev_system --host dev.mainframe.com --port 443 --user myuserid --password --reject-unauthorized false

zowe profiles create zosmf-profile test_system --host test.mainframe.com --port 443 --user myuserid --password --reject-unauthorized false

# Test connectivity
zowe zosmf check status --zosmf-profile dev_system

# List datasets
zowe files list dataset "MYUSERID.*" --zosmf-profile dev_system

# Submit JCL job
zowe jobs submit data-set "MYUSERID.JCL(COMPILE)" --zosmf-profile dev_system

Zowe API ML Configuration (instance.env):

bash# Zowe API Mediation Layer Configuration
ZOWE_PREFIX=ZWE1
ZOWE_INSTANCE=dev

# API Gateway Configuration
GATEWAY_PORT=7554
DISCOVERY_PORT=7553
CATALOG_PORT=7552

# Security Configuration
KEYSTORE_DIRECTORY=/global/zowe/keystore
KEYSTORE_PASSWORD=password
KEY_ALIAS=localhost
KEYSTORE_TYPE=PKCS12

# High Availability
HAINSTANCE_HOSTNAME=zowe-ha.company.com
HAINSTANCE_IP=192.168.1.100

# External Certificate Authority
EXTERNAL_CERTIFICATE=/global/zowe/certs/zowe-cert.pem
EXTERNAL_CERTIFICATE_AUTHORITIES=/global/zowe/certs/ca-cert.pem

Day 95-98: API Mediation Layer Deep Dive

Step 31: Master API Mediation Layer Features

  • Micro-step 31.1: Service registration and discovery
    • Service Registration: Automatic and manual service registration
    • Service Discovery: Dynamic service location and load balancing
    • Health Checks: Service availability monitoring
    • Routing Rules: Advanced request routing and transformation
  • Micro-step 31.2: Security and authentication
    • Single Sign-On (SSO): Unified authentication across services
    • JWT Token Management: Token-based authentication
    • Certificate Authentication: Client certificate validation
    • RBAC Integration: Role-based access control with mainframe security

Practical Exercise 11.2: Register z/OS Connect service with API ML:

text# service-definition.yml for API ML registration
services:
    - serviceId: customer-api
      title: Customer Management API
      description: REST API for customer operations
      catalogUiTileId: customer
      instanceBaseUrls:
        - https://zosconnect.company.com:8443
      homePageRelativeUrl: /zosConnect/services
      statusPageRelativeUrl: /zosConnect/actuator/health
      healthCheckRelativeUrl: /zosConnect/actuator/health
      routes:
        - gatewayUrl: api/v1
          serviceRelativeUrl: zosConnect/services/customerInquiry
      authentication:
        scheme: zoweJwt
      apiInfo:
        - apiId: customer.v1
          gatewayUrl: api/v1
          swaggerUrl: https://zosconnect.company.com:8443/zosConnect/services/customerInquiry/api-docs
      customMetadata:
        apiml:
          enableUrlEncodedCharacters: true
          connectTimeout: 30000
          readTimeout: 60000

API ML Service Discovery Configuration:

javascript// Service registration script
const eureka = require('eureka-js-client').Eureka;

const client = new eureka({
    instance: {
        app: 'CUSTOMER-API',
        hostName: 'zosconnect.company.com',
        ipAddr: '192.168.1.50',
        port: {
            '$': 8443,
            '@enabled': true
        },
        vipAddress: 'customer-api',
        dataCenterInfo: {
            '@class': 'com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo',
            name: 'MyOwn'
        },
        metadata: {
            'mfaas.discovery.catalogUiTile.id': 'customer',
            'mfaas.discovery.catalogUiTile.title': 'Customer Management',
            'mfaas.discovery.catalogUiTile.description': 'Customer CRUD operations',
            'mfaas.discovery.catalogUiTile.version': '1.0.0',
            'mfaas.discovery.service.title': 'Customer API',
            'mfaas.discovery.service.description': 'Mainframe customer management service',
            'mfaas.api-info.apiVersionProperties.v1.title': 'Customer Management API v1',
            'mfaas.api-info.apiVersionProperties.v1.description': 'REST API for customer operations',
            'mfaas.api-info.apiVersionProperties.v1.version': '1.0.0'
        }
    },
    eureka: {
        host: 'discovery.zowe.company.com',
        port: 7553,
        servicePath: '/eureka/apps/'
    }
});

client.start();

Building API Integration Workflows

Day 99-102: End-to-End API Development

Step 32: Complete API Integration Project

  • Micro-step 32.1: Design comprehensive API workflow
    • API Design: OpenAPI 3.0 specification creation
    • Service Orchestration: Combining multiple mainframe services
    • Error Handling: Comprehensive error management strategy
    • Performance Monitoring: API metrics and SLA monitoring
  • Micro-step 32.2: Testing and validation framework
    • Unit Testing: Individual service testing
    • Integration Testing: End-to-end workflow validation
    • Performance Testing: Load and stress testing
    • Security Testing: Authentication and authorization validation

Practical Exercise 11.3: Build complete customer management API:

OpenAPI 3.0 Specification (customer-api.yaml):

textopenapi: 3.0.1
info:
  title: Customer Management API
  description: Comprehensive customer management operations
  version: 1.0.0
  contact:
    name: API Support Team
    email: [email protected]

servers:
  - url: https://api-gateway.company.com/customer/v1
    description: Production API Gateway

paths:
  /customers/{customerId}:
    get:
      summary: Get customer details
      description: Retrieve comprehensive customer information
      parameters:
        - name: customerId
          in: path
          required: true
          schema:
            type: string
            pattern: '^[A-Z0-9]{10}$'
          example: "CUST000001"
      responses:
        '200':
          description: Customer found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CustomerResponse'
              example:
                customer:
                  customerId: "CUST000001"
                  name:
                    firstName: "John"
                    lastName: "Smith"
                  contactInfo:
                    email: "[email protected]"
                    phone: "+1-555-123-4567"
                  addresses:
                    - addressId: 1
                      type: "H"
                      street1: "123 Main St"
                      city: "New York"
                      state: "NY"
                      postalCode: "10001"
                      isPrimary: "Y"
        '404':
          description: Customer not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
    
    put:
      summary: Update customer
      description: Update existing customer information
      parameters:
        - name: customerId
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CustomerUpdateRequest'
      responses:
        '200':
          description: Customer updated successfully
        '400':
          description: Invalid request data
        '404':
          description: Customer not found
        '500':
          description: Internal server error

  /customers:
    post:
      summary: Create new customer
      description: Create a new customer record
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CustomerCreateRequest'
      responses:
        '201':
          description: Customer created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CustomerResponse'
        '400':
          description: Invalid request data
        '409':
          description: Customer already exists
        '500':
          description: Internal server error

components:
  schemas:
    CustomerResponse:
      type: object
      properties:
        customer:
          type: object
          properties:
            customerId:
              type: string
            name:
              type: object
              properties:
                firstName:
                  type: string
                lastName:
                  type: string
            contactInfo:
              type: object
              properties:
                email:
                  type: string
                phone:
                  type: string
            addresses:
              type: array
              items:
                $ref: '#/components/schemas/Address'
    
    CustomerUpdateRequest:
      type: object
      properties:
        name:
          type: object
          properties:
            firstName:
              type: string
            lastName:
              type: string
        contactInfo:
          type: object
          properties:
            email:
              type: string
            phone:
              type: string
    
    Address:
      type: object
      properties:
        addressId:
          type: integer
        type:
          type: string
          enum: ["H", "W", "M"]
        street1:
          type: string
        street2:
          type: string
        city:
          type: string
        state:
          type: string
        postalCode:
          type: string
        country:
          type: string
        isPrimary:
          type: string
          enum: ["Y", "N"]

  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT

security:
  - bearerAuth: []

Integration Test Suite (customer-api-tests.js):

javascriptconst request = require('supertest');
const expect = require('chai').expect;

const API_BASE_URL = 'https://api-gateway.company.com/customer/v1';
const TEST_CUSTOMER_ID = 'TEST000001';

describe('Customer Management API Integration Tests', () => {
    let authToken;
    
    before(async () => {
        // Authenticate and get JWT token
        const authResponse = await request(API_BASE_URL)
            .post('/auth/login')
            .send({
                username: 'testuser',
                password: 'testpass'
            });
        
        authToken = authResponse.body.token;
    });
    
    describe('Customer Creation', () => {
        it('should create a new customer successfully', async () => {
            const customerData = {
                name: {
                    firstName: 'John',
                    lastName: 'Doe'
                },
                contactInfo: {
                    email: '[email protected]',
                    phone: '+1-555-123-4567'
                }
            };
            
            const response = await request(API_BASE_URL)
                .post('/customers')
                .set('Authorization', `Bearer ${authToken}`)
                .send(customerData)
                .expect(201);
            
            expect(response.body).to.have.property('customer');
            expect(response.body.customer).to.have.property('customerId');
            expect(response.body.customer.name.firstName).to.equal('John');
        });
        
        it('should reject invalid customer data', async () => {
            const invalidData = {
                name: {
                    firstName: '' // Empty firstName should be rejected
                }
            };
            
            await request(API_BASE_URL)
                .post('/customers')
                .set('Authorization', `Bearer ${authToken}`)
                .send(invalidData)
                .expect(400);
        });
    });
    
    describe('Customer Retrieval', () => {
        it('should retrieve existing customer', async () => {
            const response = await request(API_BASE_URL)
                .get(`/customers/${TEST_CUSTOMER_ID}`)
                .set('Authorization', `Bearer ${authToken}`)
                .expect(200);
            
            expect(response.body).to.have.property('customer');
            expect(response.body.customer.customerId).to.equal(TEST_CUSTOMER_ID);
        });
        
        it('should return 404 for non-existent customer', async () => {
            await request(API_BASE_URL)
                .get('/customers/INVALID001')
                .set('Authorization', `Bearer ${authToken}`)
                .expect(404);
        });
    });
    
    describe('Performance Tests', () => {
        it('should respond within acceptable time limits', async () => {
            const startTime = Date.now();
            
            await request(API_BASE_URL)
                .get(`/customers/${TEST_CUSTOMER_ID}`)
                .set('Authorization', `Bearer ${authToken}`)
                .expect(200);
            
            const responseTime = Date.now() - startTime;
            expect(responseTime).to.be.below(2000); // Should respond within 2 seconds
        });
        
        it('should handle concurrent requests', async () => {
            const concurrentRequests = Array.from({length: 10}, () => 
                request(API_BASE_URL)
                    .get(`/customers/${TEST_CUSTOMER_ID}`)
                    .set('Authorization', `Bearer ${authToken}`)
            );
            
            const responses = await Promise.all(concurrentRequests);
            responses.forEach(response => {
                expect(response.status).to.equal(200);
            });
        });
    });
});

Week 15-16: Advanced Integration Patterns

Orchestration and Composite Services

Day 103-105: Service Orchestration Patterns

Step 33: Build Composite API Services

  • Micro-step 33.1: Design orchestration workflows
    • Sequential Orchestration: Step-by-step service invocation
    • Parallel Orchestration: Concurrent service calls with aggregation
    • Conditional Orchestration: Dynamic workflow based on data
    • Compensating Transactions: Error recovery and rollback patterns
  • Micro-step 33.2: Implement service composition
    • API Gateway Patterns: Request routing and response aggregation
    • Service Mesh: Advanced inter-service communication
    • Circuit Breaker: Fault tolerance and resilience patterns
    • Bulkhead Isolation: Resource isolation for stability

Practical Exercise 12.1: Build orchestrated customer onboarding service:

javascript// Customer Onboarding Orchestration Service
class CustomerOnboardingOrchestrator {
    constructor() {
        this.customerService = new CustomerService();
        this.accountService = new AccountService();
        this.notificationService = new NotificationService();
        this.auditService = new AuditService();
    }
    
    async onboardCustomer(onboardingRequest) {
        const transactionId = this.generateTransactionId();
        const context = {
            transactionId,
            startTime: new Date(),
            steps: []
        };
        
        try {
            // Step 1: Validate and create customer
            const customer = await this.createCustomer(onboardingRequest.customer, context);
            
            // Step 2: Create accounts in parallel
            const accounts = await this.createAccountsParallel(
                customer.customerId, 
                onboardingRequest.accounts, 
                context
            );
            
            // Step 3: Setup initial services
            const services = await this.setupServices(
                customer.customerId, 
                onboardingRequest.services, 
                context
            );
            
            // Step 4: Send welcome notifications
            await this.sendWelcomeNotifications(customer, context);
            
            // Step 5: Audit successful onboarding
            await this.auditSuccess(context, customer, accounts, services);
            
            return {
                success: true,
                transactionId,
                customer,
                accounts,
                services,
                message: "Customer onboarding completed successfully"
            };
            
        } catch (error) {
            // Compensating transaction - rollback partial changes
            await this.rollbackOnboarding(context, error);
            throw error;
        }
    }
    
    async createCustomer(customerData, context) {
        const step = { name: 'createCustomer', startTime: new Date() };
        context.steps.push(step);
        
        try {
            const customer = await this.customerService.createCustomer(customerData);
            step.endTime = new Date();
            step.success = true;
            step.customerId = customer.customerId;
            return customer;
        } catch (error) {
            step.endTime = new Date();
            step.success = false;
            step.error = error.message;
            throw error;
        }
    }
    
    async createAccountsParallel(customerId, accountRequests, context) {
        const step = { name: 'createAccounts', startTime: new Date() };
        context.steps.push(step);
        
        try {
            const accountPromises = accountRequests.map(accountReq => 
                this.accountService.createAccount(customerId, accountReq)
            );
            
            const accounts = await Promise.allSettled(accountPromises);
            
            const successfulAccounts = accounts
                .filter(result => result.status === 'fulfilled')
                .map(result => result.value);
            
            const failedAccounts = accounts
                .filter(result => result.status === 'rejected')
                .map(result => result.reason);
            
            if (failedAccounts.length > 0) {
                throw new Error(`Failed to create ${failedAccounts.length} accounts`);
            }
            
            step.endTime = new Date();
            step.success = true;
            step.accountCount = successfulAccounts.length;
            
            return successfulAccounts;
        } catch (error) {
            step.endTime = new Date();
            step.success = false;
            step.error = error.message;
            throw error;
        }
    }
    
    async rollbackOnboarding(context, originalError) {
        console.log(`Rolling back onboarding transaction: ${context.transactionId}`);
        
        // Rollback in reverse order of creation
        for (let i = context.steps.length - 1; i >= 0; i--) {
            const step = context.steps[i];
            
            try {
                switch (step.name) {
                    case 'createCustomer':
                        if (step.success && step.customerId) {
                            await this.customerService.deleteCustomer(step.customerId);
                        }
                        break;
                    case 'createAccounts':
                        // Additional rollback logic for accounts
                        break;
                }
            } catch (rollbackError) {
                console.error(`Rollback failed for step ${step.name}:`, rollbackError);
            }
        }
        
        // Log rollback completion
        await this.auditService.logRollback(context, originalError);
    }
}

Day 106-109: Performance Optimization and Monitoring

Step 34: Implement Comprehensive Monitoring

  • Micro-step 34.1: API performance monitoring
    • Response Time Tracking: Detailed timing measurements
    • Throughput Monitoring: Request volume and capacity planning
    • Error Rate Analysis: Success/failure ratio tracking
    • Resource Utilization: CPU, memory, and network usage
  • Micro-step 34.2: Business metrics and alerting
    • SLA Monitoring: Service level agreement compliance
    • Business KPIs: Transaction success rates, customer satisfaction
    • Proactive Alerting: Threshold-based notifications
    • Dashboards: Real-time operational visibility

Practical Exercise 12.2: Implement comprehensive monitoring solution:

javascript// Comprehensive API Monitoring Framework
class APIMonitoringFramework {
    constructor() {
        this.metricsCollector = new MetricsCollector();
        this.alertManager = new AlertManager();
        this.dashboardService = new DashboardService();
    }
    
    // Middleware for automatic metrics collection
    createMonitoringMiddleware() {
        return (req, res, next) => {
            const startTime = Date.now();
            const requestId = this.generateRequestId();
            
            req.monitoring = {
                requestId,
                startTime,
                endpoint: req.path,
                method: req.method
            };
            
            // Override res.end to capture response metrics
            const originalEnd = res.end;
            res.end = function(...args) {
                const endTime = Date.now();
                const duration = endTime - startTime;
                
                // Collect metrics
                this.metricsCollector.recordRequest({
                    requestId,
                    endpoint: req.path,
                    method: req.method,
                    statusCode: res.statusCode,
                    duration,
                    timestamp: new Date(startTime)
                });
                
                // Check for SLA violations
                this.checkSLAViolations(req.path, duration, res.statusCode);
                
                originalEnd.apply(res, args);
            }.bind(this);
            
            next();
        };
    }
    
    checkSLAViolations(endpoint, duration, statusCode) {
        const slaConfig = this.getSLAConfig(endpoint);
        
        if (duration > slaConfig.maxResponseTime) {
            this.alertManager.sendAlert({
                type: 'SLA_VIOLATION',
                severity: 'HIGH',
                endpoint,
                duration,
                threshold: slaConfig.maxResponseTime,
                message: `Response time ${duration}ms exceeded SLA threshold ${slaConfig.maxResponseTime}ms`
            });
        }
        
        if (statusCode >= 500) {
            this.alertManager.sendAlert({
                type: 'ERROR_RATE',
                severity: 'CRITICAL',
                endpoint,
                statusCode,
                message: `Server error detected on ${endpoint}`
            });
        }
    }
    
    getSLAConfig(endpoint) {
        const slaDefaults = {
            maxResponseTime: 2000, // 2 seconds
            maxErrorRate: 0.01 // 1%
        };
        
        const endpointSLAs = {
            '/customers': { maxResponseTime: 1500 },
            '/customers/search': { maxResponseTime: 3000 },
            '/customers/bulk': { maxResponseTime: 5000 }
        };
        
        return { ...slaDefaults, ...endpointSLAs[endpoint] };
    }
    
    generateHourlyReport() {
        const metrics = this.metricsCollector.getHourlyMetrics();
        
        return {
            timestamp: new Date(),