Skip to content

gperkinscgi/ims-connect-java-server

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

IMS Connect Java Server

A high-performance, enterprise-grade Java server implementation for IBM IMS Connect protocol communication. This server acts as a gateway between modern applications and IBM mainframe IMS systems, providing secure, scalable, and monitored connectivity.

Features

Core Capabilities

  • High Performance: Built on Netty NIO framework for maximum throughput
  • Enterprise Security: SSL/TLS with mutual authentication, RACF integration, audit logging
  • Connection Pooling: Intelligent load balancing across multiple mainframe backends
  • Monitoring: Prometheus metrics, health checks, and structured logging
  • Spring Boot Integration: Enterprise-ready with auto-configuration
  • Kubernetes Ready: Production deployment manifests included

Protocol Support

  • IMS Connect Protocol: Full compliance with IBM IMS Connect protocol and HWSSMPL1 exit routine
  • OTMA Support: Open Transaction Manager Access with conversational transactions
  • System Messages: Built-in PING, NOTIFY, ECHO, and STATUS message handlers
  • Legacy Compatibility: Supports both modern OTMA and legacy IMS Connect clients

Advanced Features

  • Conversational Transactions: Multi-message transaction sequences with state management
  • RACF Security: Resource Access Control Facility integration with token validation
  • Message Segmentation: Enhanced LL/ZZ message format support
  • Protocol Routing: Automatic detection and routing between OTMA and legacy protocols

Architecture

┌─────────────────┐    ┌──────────────────────────────────┐    ┌─────────────────┐
│   Client Apps   │───▶│        IMS Connect Java Server   │───▶│   Mainframe     │
│                 │    │                                  │    │   IMS Systems   │
│ • Legacy IMS    │    │  ┌─────────────────────────────┐ │    │                 │
│ • OTMA Clients  │    │  │     Protocol Router         │ │    │ • IMS TM        │
│ • System Tools  │    │  │   (Legacy/OTMA Detection)   │ │    │ • RACF Security │
│                 │    │  └─────────────────────────────┘ │    │ • OTMA Support  │
└─────────────────┘    │                                  │    └─────────────────┘
                       │  ┌─────────────────────────────┐ │
                       │  │    Transaction Handlers     │ │
                       │  │ • Banking • System Messages │ │
                       │  │ • Security • Conversational │ │
                       │  └─────────────────────────────┘ │
                       │                                  │
                       │  ┌─────────────────────────────┐ │
                       │  │    Security & Monitoring    │ │
                       │  │ • RACF Integration          │ │
                       │  │ • Audit Logging             │ │
                       │  │ • Health Checks (PING)      │ │
                       │  └─────────────────────────────┘ │
                       └──────────────────────────────────┘
                                          │
                                          ▼
                                   ┌──────────────────┐
                                   │   Monitoring     │
                                   │ (Prometheus,     │
                                   │  Grafana, Logs)  │
                                   └──────────────────┘

Quick Start

Prerequisites

  • Java 17 or higher
  • Maven 3.6+
  • Docker (optional)
  • Kubernetes cluster (optional)

Development Setup

git clone https://github.com/gperkinscgi/ims-connect-java-server.git
cd ims-connect-java-server

# Automated development setup
./scripts/dev-setup.sh

# Edit your configuration
vi .env

# Start development server
./scripts/run-dev.sh

The setup script will:

  • Create .env file from template
  • Generate self-signed SSL certificates for development
  • Verify Java and Maven requirements
  • Build the project

Manual Setup

# Copy environment template
cp .env.example .env

# Build the project
mvn clean package

# Run with development profile
mvn spring-boot:run -Dspring-boot.run.profiles=development

# Or using JAR
java -jar target/ims-connect-java-server-1.0.0.jar --spring.profiles.active=development

Docker Deployment

# Build image
docker build -t ims-connect-server .

# Run with Docker Compose (includes monitoring)
docker-compose up -d

# View logs
docker-compose logs -f ims-connect-server

Kubernetes Deployment

# Deploy to Kubernetes
kubectl apply -f k8s/

# Check status
kubectl get pods -n ims-connect

# View logs
kubectl logs -f deployment/ims-connect-server -n ims-connect

Configuration

Development Configuration (.env file)

For development, all secrets and configuration are managed through a .env file:

# SSL Certificate Passwords
SSL_KEYSTORE_PASSWORD=changeme
SSL_KEY_PASSWORD=changeme
SSL_TRUSTSTORE_PASSWORD=changeme

# Mainframe Backend Configuration
MAINFRAME_HOST_1=localhost
MAINFRAME_PORT_1=9999
MAINFRAME_HOST_2=localhost
MAINFRAME_PORT_2=9998

# Security Configuration
ADMIN_PASSWORD=admin123
MONITOR_PASSWORD=monitor123

# Application Settings
LOG_LEVEL=DEBUG
JVM_OPTS=-Xmx1g -Xms512m

Security Features:

  • .env files are Git-ignored
  • ✅ Only loaded in development profiles
  • ✅ Fallback to safe defaults if missing
  • ✅ Template provided (.env.example)

Application Properties

The server supports multiple configuration profiles:

Development Profile (application-development.yml):

ims-connect:
  server:
    port: 9999
    datastore-name: "DEV-IMS"
    worker-threads: 4            # Reduced for development

  backends:
    - name: "dev-mainframe-1"
      host: "${MAINFRAME_HOST_1:localhost}"
      port: ${MAINFRAME_PORT_1:9999}
      ssl-enabled: false         # Disabled for local dev

  security:
    ssl:
      enabled: false             # SSL disabled for local development
      keystore-password: "${SSL_KEYSTORE_PASSWORD:devpassword}"

Production Profile (application.yml):

ims-connect:
  server:
    port: 9999
    boss-threads: 2
    worker-threads: 8

  security:
    enabled: true
    ssl:
      enabled: true
      keystore-path: "config/ssl/server.p12"
      keystore-password: "${SSL_KEYSTORE_PASSWORD}"

Environment Variables Reference

Variable Description Development Default
SPRING_PROFILES_ACTIVE Active Spring profile development
SSL_KEYSTORE_PASSWORD SSL keystore password devpassword
SSL_KEY_PASSWORD SSL key password devpassword
SSL_TRUSTSTORE_PASSWORD SSL truststore password devpassword
MAINFRAME_HOST_1 Primary mainframe host localhost
MAINFRAME_PORT_1 Primary mainframe port 9999
MAINFRAME_HOST_2 Secondary mainframe host localhost
MAINFRAME_PORT_2 Secondary mainframe port 9998
ADMIN_PASSWORD Admin user password admin
MONITOR_PASSWORD Monitor user password monitor
LOG_LEVEL Application log level DEBUG
JVM_OPTS JVM options -Xmx1g -Xms512m

OTMA and System Messages

OTMA Support

The server includes comprehensive OTMA (Open Transaction Manager Access) support for enhanced IMS messaging:

ims-connect:
  otma:
    enabled: true
    conversations:
      enabled: true
      max-conversations: 1000
      conversation-timeout-ms: 300000  # 5 minutes
    security:
      racf-enabled: true
      audit-enabled: true
      token-validation-enabled: true

OTMA Features:

  • Conversational Transactions: Multi-message sequences with state management
  • Enhanced Message Segmentation: LL/ZZ format support for complex messages
  • Protocol Auto-Detection: Automatic routing between OTMA and legacy clients
  • RACF Integration: Full security token validation and authorization
  • Audit Logging: Comprehensive transaction audit trails

System Messages

Built-in system message handlers for operational management:

ims-connect:
  system-messages:
    enabled: true
    ping-enabled: true     # Health check messages
    notify-enabled: true   # System notifications
    echo-enabled: true     # Connectivity testing
    status-enabled: true   # Server status queries

System Message Types:

Message Purpose Response
PING Health checks PONG with timestamp and server status
NOTIFY System notifications Acknowledgment with appropriate log level
ECHO Connectivity testing Exact echo of sent data
STATUS Server information Runtime stats (memory, CPU, uptime)

Usage Examples:

# Health check via PING
echo "PING TEST_DATA" | nc localhost 9999

# Server status query
echo "STATUS" | nc localhost 9999

# Connectivity test
echo "ECHO Hello World" | nc localhost 9999

Example Implementation

The server includes example transaction handlers in the examples package to demonstrate proper implementation patterns. These are for demonstration only and should not be used in production.

To enable examples in development:

ims-connect:
  examples:
    enabled: true

Example Transaction Handler

// Located in com.cgi.icbc.imsconnect.examples.handlers
@Component
public class BankingTransactionHandler implements IMSTransactionHandler {

    private static final Logger logger = LoggerFactory.getLogger(BankingTransactionHandler.class);
    private final AuditLogger auditLogger;
    private final AccountService accountService;

    @Autowired
    public BankingTransactionHandler(AuditLogger auditLogger, AccountService accountService) {
        this.auditLogger = auditLogger;
        this.accountService = accountService;
    }

    @Override
    public boolean canHandle(String transactionCode) {
        // Handle banking transaction codes
        return "BALINQ".equals(transactionCode) || "TRANSFER".equals(transactionCode);
    }

    @Override
    public IMSResponse handleTransaction(IRMHeader header, String messageData) {
        String clientId = header.getClientId();
        String transactionCode = header.getTransactionCode();

        try {
            // Convert EBCDIC message from mainframe client to ASCII
            String asciiMessage = EbcdicConverter.ebcdicToAscii(messageData);

            // Route to appropriate handler based on transaction code
            IMSResponse response = switch (transactionCode) {
                case "BALINQ" -> handleBalanceInquiry(header, asciiMessage);
                case "TRANSFER" -> handleFundsTransfer(header, asciiMessage);
                default -> createErrorResponse("Unknown transaction code: " + transactionCode);
            };

            // Audit successful transaction
            auditLogger.logTransaction("TRANSACTION_PROCESSED", clientId,
                transactionCode, null, true, "Message length: " + messageData.length());

            return response;

        } catch (Exception e) {
            logger.error("Failed to process transaction {} for client {}", transactionCode, clientId, e);
            auditLogger.logTransaction("TRANSACTION_FAILED", clientId,
                transactionCode, null, false, "Error: " + e.getMessage());
            return createErrorResponse("Transaction processing failed: " + e.getMessage());
        }
    }

    private IMSResponse handleBalanceInquiry(IRMHeader header, String messageData) {
        // Parse incoming message (fixed-format from mainframe client)
        String accountNumber = messageData.substring(8, 24).trim();   // Account number
        String customerNumber = messageData.substring(24, 36).trim(); // Customer number

        logger.info("Processing balance inquiry for account: {}, customer: {}",
                   accountNumber, customerNumber);

        // Call business logic
        AccountBalance balance = accountService.getAccountBalance(accountNumber);

        // Build response message in fixed format expected by mainframe client
        StringBuilder response = new StringBuilder();
        response.append(String.format("%-8s", "BALINQ"));                    // Echo transaction code
        response.append(String.format("%-4s", "0000"));                      // Response code (0000 = success)
        response.append(String.format("%-16s", accountNumber));              // Account number
        response.append(String.format("%015d", balance.getAmountCents()));   // Balance in cents (15 digits)
        response.append(String.format("%-3s", balance.getCurrencyCode()));   // Currency code
        response.append(String.format("%-1s", balance.getAccountStatus()));  // Account status
        response.append(String.format("%-50s", " "));                        // Reserved space

        // Convert response back to EBCDIC for mainframe client
        String ebcdicResponse = EbcdicConverter.asciiToEbcdic(response.toString());

        return IMSResponse.success(ebcdicResponse);
    }

    private IMSResponse handleFundsTransfer(IRMHeader header, String messageData) {
        // Parse transfer request
        String fromAccount = messageData.substring(8, 24).trim();
        String toAccount = messageData.substring(24, 40).trim();
        long amountCents = Long.parseLong(messageData.substring(40, 55).trim());

        logger.info("Processing funds transfer: {} -> {}, amount: {}",
                   fromAccount, toAccount, amountCents);

        // Call business logic
        TransferResult result = accountService.transferFunds(fromAccount, toAccount, amountCents);

        // Build response
        StringBuilder response = new StringBuilder();
        response.append(String.format("%-8s", "TRANSFER"));
        response.append(String.format("%-4s", result.isSuccess() ? "0000" : "1001"));
        response.append(String.format("%-16s", fromAccount));
        response.append(String.format("%-16s", toAccount));
        response.append(String.format("%-20s", result.getTransactionId()));
        response.append(String.format("%-50s", result.getMessage()));

        String ebcdicResponse = EbcdicConverter.asciiToEbcdic(response.toString());
        return result.isSuccess() ?
            IMSResponse.success(ebcdicResponse) :
            IMSResponse.error(ebcdicResponse);
    }

    private IMSResponse createErrorResponse(String errorMessage) {
        StringBuilder response = new StringBuilder();
        response.append(String.format("%-8s", "ERROR"));
        response.append(String.format("%-4s", "9999"));  // General error code
        response.append(String.format("%-100s", errorMessage));

        String ebcdicResponse = EbcdicConverter.asciiToEbcdic(response.toString());
        return IMSResponse.error(ebcdicResponse);
    }
}

### Example Business Service Layer

```java
// Located in com.cgi.icbc.imsconnect.examples.service
@Service
public class AccountService {

    private static final Logger logger = LoggerFactory.getLogger(AccountService.class);

    // Example mock data - in real implementation, this would call database/external services
    private final Map<String, AccountBalance> accounts = new HashMap<>();

    @PostConstruct
    public void initializeTestData() {
        accounts.put("1234567890123456", new AccountBalance(
            "1234567890123456", 150000L, "CAD", "A")); // $1,500.00 CAD
        accounts.put("9876543210987654", new AccountBalance(
            "9876543210987654", 250000L, "USD", "A")); // $2,500.00 USD
    }

    public AccountBalance getAccountBalance(String accountNumber) {
        AccountBalance balance = accounts.get(accountNumber);
        if (balance == null) {
            throw new AccountNotFoundException("Account not found: " + accountNumber);
        }
        return balance;
    }

    public TransferResult transferFunds(String fromAccount, String toAccount, long amountCents) {
        try {
            AccountBalance fromBalance = getAccountBalance(fromAccount);
            AccountBalance toBalance = getAccountBalance(toAccount);

            if (fromBalance.getAmountCents() < amountCents) {
                return TransferResult.failure("Insufficient funds");
            }

            // Perform transfer
            fromBalance.setAmountCents(fromBalance.getAmountCents() - amountCents);
            toBalance.setAmountCents(toBalance.getAmountCents() + amountCents);

            String transactionId = "TXN" + System.currentTimeMillis();
            logger.info("Transfer completed: {} -> {}, amount: {}, txnId: {}",
                       fromAccount, toAccount, amountCents, transactionId);

            return TransferResult.success(transactionId, "Transfer completed successfully");

        } catch (Exception e) {
            logger.error("Transfer failed: {} -> {}", fromAccount, toAccount, e);
            return TransferResult.failure("Transfer failed: " + e.getMessage());
        }
    }
}

3. Data Models

@Data
@AllArgsConstructor
@NoArgsConstructor
public class AccountBalance {
    private String accountNumber;
    private Long amountCents;      // Store money as cents to avoid decimal precision issues
    private String currencyCode;   // "CAD", "USD", etc.
    private String accountStatus;  // "A" = Active, "C" = Closed, "F" = Frozen

    public BigDecimal getAmount() {
        return BigDecimal.valueOf(amountCents).divide(BigDecimal.valueOf(100));
    }
}

@Data
@AllArgsConstructor
public class TransferResult {
    private boolean success;
    private String transactionId;
    private String message;

    public static TransferResult success(String transactionId, String message) {
        return new TransferResult(true, transactionId, message);
    }

    public static TransferResult failure(String message) {
        return new TransferResult(false, null, message);
    }
}

// Custom exceptions
public class AccountNotFoundException extends RuntimeException {
    public AccountNotFoundException(String message) {
        super(message);
    }

4. Handler Registration

@Configuration
public class TransactionHandlerConfiguration {

    @Bean
    public IMSTransactionHandlerRegistry handlerRegistry(
            List<IMSTransactionHandler> handlers,
            DefaultIMSServerHandler serverHandler) {

        IMSTransactionHandlerRegistry registry = new IMSTransactionHandlerRegistry();

        // Register all transaction handlers
        handlers.forEach(registry::registerHandler);

        // Set the registry in the server handler
        serverHandler.setTransactionHandlerRegistry(registry);

        return registry;
    }
}

5. Testing the Server

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@TestPropertySource(properties = {
    "ims-connect.backends[0].host=localhost",
    "ims-connect.backends[0].port=9999",
    "ims-connect.security.enabled=false"
})
class BankingTransactionHandlerTest {

    @Autowired
    private BankingTransactionHandler handler;

    @Test
    void testBalanceInquiryHandler() {
        // Arrange - create IRM header
        IRMHeader header = IRMHeader.builder()
            .transactionCode("BALINQ")
            .clientId("TEST_CLIENT")
            .architecture(IRMHeader.IRMARCH1)
            .flags(IRMHeader.IRMSYNCH)
            .build();

        // Create message in EBCDIC format (as it would come from mainframe client)
        String message = String.format("%-8s%-16s%-12s%-50s",
            "BALINQ", "1234567890123456", "CUST123", " ");
        String ebcdicMessage = EbcdicConverter.asciiToEbcdic(message);

        // Act
        IMSResponse response = handler.handleTransaction(header, ebcdicMessage);

        // Assert
        assertThat(response.isSuccess()).isTrue();
        assertThat(response.getData()).isNotEmpty();

        // Verify response format
        String asciiResponse = EbcdicConverter.ebcdicToAscii(response.getData());
        assertThat(asciiResponse.substring(0, 8).trim()).isEqualTo("BALINQ");
        assertThat(asciiResponse.substring(8, 12).trim()).isEqualTo("0000"); // Success code
    }

    @Test
    void testCanHandleTransactionCodes() {
        assertThat(handler.canHandle("BALINQ")).isTrue();
        assertThat(handler.canHandle("TRANSFER")).isTrue();
        assertThat(handler.canHandle("UNKNOWN")).isFalse();
    }
}

6. Client Connection Example

Here's how a mainframe COBOL program would connect to this server:

      * COBOL client connecting to IMS Connect Java Server
       IDENTIFICATION DIVISION.
       PROGRAM-ID. ACCOUNT-INQUIRY.

       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  WS-IMS-HEADER.
           05  WS-IRM-LENGTH        PIC 9(8) COMP.
           05  WS-IRM-ARCH          PIC X(4) VALUE 'IRM1'.
           05  WS-IRM-FLAGS         PIC 9(4) COMP VALUE 1.
           05  WS-TXN-CODE          PIC X(8) VALUE 'BALINQ  '.
           05  WS-CLIENT-ID         PIC X(8) VALUE 'COBOL001'.

       01  WS-BALANCE-REQUEST.
           05  WS-REQ-TXN-CODE      PIC X(8) VALUE 'BALINQ  '.
           05  WS-REQ-ACCOUNT       PIC X(16).
           05  WS-REQ-CUSTOMER      PIC X(12).
           05  FILLER               PIC X(50) VALUE SPACES.

       01  WS-BALANCE-RESPONSE.
           05  WS-RESP-TXN-CODE     PIC X(8).
           05  WS-RESP-CODE         PIC X(4).
           05  WS-RESP-ACCOUNT      PIC X(16).
           05  WS-RESP-BALANCE      PIC 9(15).
           05  WS-RESP-CURRENCY     PIC X(3).
           05  WS-RESP-STATUS       PIC X(1).
           05  FILLER               PIC X(50).

       PROCEDURE DIVISION.
       MAIN-LOGIC.
           MOVE '1234567890123456' TO WS-REQ-ACCOUNT
           MOVE 'CUST123     '     TO WS-REQ-CUSTOMER

      *    Connect to IMS Connect Java Server
           CALL 'HWSSMPL1' USING
               WS-IMS-HEADER
               WS-BALANCE-REQUEST
               WS-BALANCE-RESPONSE

           IF WS-RESP-CODE = '0000'
               DISPLAY 'Account Balance: ' WS-RESP-BALANCE
               DISPLAY 'Currency: ' WS-RESP-CURRENCY
           ELSE
               DISPLAY 'Error: ' WS-RESP-CODE
           END-IF

           STOP RUN.

How It Works

This IMS Connect Java Server acts as a gateway that:

  1. Receives IMS Connect protocol messages from mainframe clients (COBOL programs, etc.)
  2. Parses the EBCDIC-encoded messages and IRM headers
  3. Routes transactions to appropriate business logic handlers based on transaction codes
  4. Processes the business logic (account lookups, transfers, etc.)
  5. Returns properly formatted EBCDIC responses back to the mainframe clients

Message Flow

Mainframe Client (COBOL)
    ↓ (EBCDIC message via IMS Connect protocol)
IMS Connect Java Server
    ↓ (Parse & Convert to ASCII)
Transaction Handler (Java business logic)
    ↓ (Call business services)
Database/External Systems
    ↓ (Return results)
Transaction Handler
    ↓ (Format & Convert to EBCDIC)
IMS Connect Java Server
    ↓ (IMS Connect protocol response)
Mainframe Client receives response

Monitoring and Metrics

Health Checks

Spring Boot Actuator Endpoints:

# Basic health check
curl http://localhost:8080/actuator/health

# Detailed health check (includes system message validation)
curl -u admin:admin http://localhost:8080/actuator/health

# System message health check (internal PING test)
curl http://localhost:8080/actuator/health/systemMessage

IMS Connect Protocol Health Checks:

# Direct PING to IMS Connect port
echo "PING HEALTH_CHECK" | nc localhost 9999

# Server status via STATUS message
echo "STATUS" | nc localhost 9999

# Echo test for connectivity
echo "ECHO CONNECTION_TEST" | nc localhost 9999

Prometheus Metrics

Core Metrics:

  • ims_connect_active_connections - Current active connections
  • ims_connect_pool_size - Connection pool size by backend
  • ims_connect_transactions_total - Total transactions processed
  • ims_connect_transaction_duration_seconds - Transaction response times
  • ims_connect_backend_health_status - Backend health status

OTMA Metrics:

  • ims_connect_otma_conversations_active - Active conversational transactions
  • ims_connect_otma_conversations_total - Total conversations started
  • ims_connect_otma_messages_total - OTMA messages processed by type
  • ims_connect_protocol_routing_total - Protocol routing decisions (OTMA vs Legacy)

System Message Metrics:

  • ims_connect_system_messages_total - System messages by type (PING, NOTIFY, ECHO, STATUS)
  • ims_connect_ping_response_time_seconds - PING response times
  • ims_connect_health_check_status - System message health check results

Security Metrics:

  • ims_connect_racf_validations_total - RACF security validations
  • ims_connect_security_failures_total - Security validation failures
  • ims_connect_audit_events_total - Audit events logged

Logging

Structured JSON logs are written to multiple files:

  • logs/ims-connect-server.log - Application logs
  • logs/ims-connect-audit.log - Audit trail (JSON format)
  • logs/ims-connect-metrics.log - Performance metrics
  • logs/ims-connect-errors.log - Error-only logs

Security

SSL/TLS Configuration

ims-connect:
  security:
    ssl:
      enabled: true
      keystore-path: "config/ssl/server.p12"
      keystore-password: "${SSL_KEYSTORE_PASSWORD}"
      truststore-path: "config/ssl/truststore.p12"  # For mutual auth
      truststore-password: "${SSL_TRUSTSTORE_PASSWORD}"
      enabled-protocols: ["TLSv1.3", "TLSv1.2"]

Authentication

HTTP Basic authentication for management endpoints:

  • Username: admin / Password: admin (change in production)
  • Username: monitor / Password: monitor

Troubleshooting

Development Issues

  1. Missing .env file

    # Run setup script
    ./scripts/dev-setup.sh
    
    # Or manually copy template
    cp .env.example .env
  2. Environment variables not loading

    # Check if development profile is active
    grep "Active profiles" logs/ims-connect-server.log
    
    # Verify .env file exists and has correct values
    cat .env | grep -v PASSWORD
    
    # Start with explicit development profile
    mvn spring-boot:run -Dspring-boot.run.profiles=development
  3. SSL Certificate Issues (Development)

    # Regenerate development certificates
    rm -rf config/ssl/dev-*.p12
    ./scripts/dev-setup.sh
    
    # Verify certificate
    keytool -list -keystore config/ssl/dev-keystore.p12 -storepass devpassword
  4. Authentication Failed

    # Check if passwords are loaded from .env
    grep ADMIN_PASSWORD .env
    
    # Test with default credentials
    curl -u admin:admin123 http://localhost:8080/actuator/health

Production Issues

  1. Connection Refused

    # Check if backends are reachable
    telnet mainframe-host 9999
    
    # Verify configuration
    kubectl get configmap ims-connect-config -o yaml
  2. SSL Handshake Failures

    # Verify certificates
    openssl s_client -connect mainframe-host:9999 -cert client.pem
    
    # Check Java keystore
    keytool -list -keystore config/ssl/keystore.p12
  3. High Memory Usage

    # Check JVM settings
    kubectl describe pod ims-connect-server-xxx
    
    # Monitor heap usage
    curl http://localhost:8080/actuator/metrics/jvm.memory.used

Log Analysis

# View audit logs
tail -f logs/ims-connect-audit.log | jq .

# Search for errors
grep "ERROR" logs/ims-connect-server.log

# Monitor transactions
grep "TRANSACTION" logs/ims-connect-audit.log | jq '.eventType, .success, .transactionCode'

Performance Tuning

Development Performance

For development, performance settings are optimized for quick startup:

# In .env file
JVM_OPTS=-Xmx1g -Xms512m -XX:+UseG1GC

# Or via environment variable
export JAVA_OPTS="-Xmx1g -Xms512m -XX:+UseG1GC"
./scripts/run-dev.sh

Production JVM Tuning

export JAVA_OPTS="-Xmx2g -Xms1g -XX:+UseG1GC -XX:MaxGCPauseMillis=200"

Netty Tuning

ims-connect:
  server:
    boss-threads: 2      # Number of CPU cores
    worker-threads: 16   # 2x CPU cores
    backlog-size: 2048   # Increase for high load

Connection Pool Tuning

ims-connect:
  pool:
    min-connections-per-backend: 5
    max-connections-per-backend: 50
    connection-timeout-ms: 3000

Examples Package

The project includes comprehensive examples in the com.cgi.icbc.imsconnect.examples package:

  • Transaction Handlers: examples.handlers - Sample implementations for banking transactions
  • Services: examples.service - Mock business logic services
  • Configuration: examples.config - Auto-configuration for examples

Important: Examples are disabled by default and should only be enabled in development environments:

ims-connect:
  examples:
    enabled: true  # Only for development/testing

Examples demonstrate:

  • OTMA conversational transactions
  • RACF security integration
  • EBCDIC message processing
  • Error handling patterns
  • Transaction lifecycle management

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages