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 DB2, modern 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(),