Skip to content

Part 13 — Build Integration

13.1 Overview

The PLI Platform integrates with modern build systems (Gradle, Maven) to automate the compilation, enhancement, and packaging of PL/I applications. This section covers end-to-end build automation.

Build Pipeline Overview

PL/I Source Files
[1] PLI Compiler (pli_compiler2.jar)
Generated Java Source + Annotations
[2] javac + Manifold Plugin
Enhanced .class Files + Metadata
[3] Packaging (JAR/WAR)
Deployable Artifact

13.2 Gradle Integration

13.2.1 Basic Gradle Configuration

Complete build.gradle for PLI project:

plugins {
    id 'java'
    id 'war'  // For CICS web applications
}

group = 'com.yourcompany'
version = '1.0.0'

repositories {
    mavenCentral()
    maven {
        url 'https://your-artifact-repository/maven'
        credentials {
            username = project.findProperty('repoUser') ?: ''
            password = project.findProperty('repoPassword') ?: ''
        }
    }
}

// Dependencies
dependencies {
    // PLI Runtime (required)
    implementation 'com.heirloom:pli_runtime2:26.2.27.RC1'

    // Manifold (compile-time annotation processor)
    annotationProcessor 'com.heirloom:heirloom-manifold:2.0.0'
    implementation 'systems.manifold:manifold-props-rt:2024.1.42'

    // For CICS applications
    compileOnly 'jakarta.platform:jakarta.jakartaee-api:10.0.0'

    // For SQL/JDBC
    runtimeOnly 'com.ibm.db2:jcc:11.5.8.0'
    // Or PostgreSQL: runtimeOnly 'org.postgresql:postgresql:42.7.1'

    // For IBM MQ (if needed)
    implementation 'com.ibm.mq:com.ibm.mq.allclient:9.3.4.0'

    // Testing
    testImplementation 'org.junit.jupiter:junit-jupiter:5.10.0'
    testImplementation 'org.mockito:mockito-core:5.8.0'
}

// Source directories
sourceSets {
    main {
        java {
            srcDirs = ['generated', 'src/main/java']
        }
        resources {
            srcDirs = ['src/main/resources']
        }
    }
}

// PLI Compiler configuration
ext {
    pliCompilerJar = file("${projectDir}/lib/pli_compiler2-26.2.27.RC1.jar")
    pliSourceDir = file('src/main/pli')
    javaTargetDir = file('generated')

    // Compilation strategy: 'static' for batch, 'instance' for CICS
    pliStrategy = project.findProperty('pliStrategy') ?: 'static'
}

// Task: Compile PL/I to Java
task compilePli(type: Exec) {
    description = 'Compile PL/I source files to Java'
    group = 'build'

    workingDir projectDir

    // Build command line
    def args = [
        'java', '-jar', pliCompilerJar,
        '--source', pliSourceDir,
        '--target', javaTargetDir,
        '--package', 'com.yourcompany.app',
        '--strategy', pliStrategy,
        '--cics',           // Enable CICS support
        '--sql',            // Enable SQL support
        '--loglevel', 'INFO'
    ]

    // Optional: Helper configuration
    def helperFile = file('src/main/resources/helper.json')
    if (helperFile.exists()) {
        args += ['--helper', helperFile.absolutePath]
    }

    commandLine args

    // Inputs/outputs for incremental build
    inputs.dir(pliSourceDir)
    outputs.dir(javaTargetDir)

    // Create output directory
    doFirst {
        javaTargetDir.mkdirs()
    }
}

// Run PLI compilation before Java compilation
compileJava.dependsOn compilePli

// Configure javac to use Manifold plugin
tasks.withType(JavaCompile) {
    options.compilerArgs += [
        '-Xplugin:Manifold',
        '--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED',
        '--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED',
        '--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED',
        '--add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED',
        '--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED',
        '--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED'
    ]
    options.fork = true
    options.forkOptions.jvmArgs += [
        '--add-opens=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED',
        '--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED',
        '--add-opens=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED',
        '--add-opens=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED'
    ]
}

// Task: Run a specific program (for batch testing)
task runProgram(type: JavaExec) {
    description = 'Run a specific PL/I program'
    group = 'application'

    classpath = sourceSets.main.runtimeClasspath
    mainClass = project.findProperty('mainClass') ?: 'com.yourcompany.app.MAIN'
    args = (project.findProperty('args') ?: '').split(',')

    // Set system properties for runtime
    systemProperty 'pli.config', 'config/pli.properties'
}

// Task: Create WAR for CICS deployment
war {
    archiveBaseName = 'myapp-cics'
    archiveVersion = version

    // Include generated classes
    from(sourceSets.main.output) {
        include '**/*.class'
    }
}

// Task: Create JAR for batch deployment
task batchJar(type: Jar) {
    description = 'Create JAR for batch execution'
    group = 'build'

    archiveBaseName = 'myapp-batch'
    archiveVersion = version

    from sourceSets.main.output

    manifest {
        attributes(
            'Main-Class': 'com.yourcompany.app.BatchMain',
            'Implementation-Version': version
        )
    }
}

// Clean task
clean {
    delete javaTargetDir
}

13.2.2 Multi-Module Gradle Project

For large projects with multiple waves or modules:

settings.gradle:

rootProject.name = 'enterprise-batch-system'

include 'common'
include 'wave1'
include 'wave2'
include 'wave3'
include 'wave4'
include 'wave5'

Root build.gradle:

subprojects {
    apply plugin: 'java'

    repositories {
        mavenCentral()
    }

    dependencies {
        implementation 'com.heirloom:pli_runtime2:26.2.27.RC1'
        annotationProcessor 'com.heirloom:heirloom-manifold:2.0.0'
    }

    // Common PLI compilation configuration
    ext {
        pliCompilerJar = rootProject.file('lib/pli_compiler2-26.2.27.RC1.jar')
    }
}

wave1/build.gradle:

// Wave-specific configuration
ext {
    pliSourceDir = file('src/main/pli')
    javaTargetDir = file('generated')
}

task compilePli(type: Exec) {
    // Same as before, but wave-specific
    commandLine 'java', '-jar', pliCompilerJar,
        '--source', pliSourceDir,
        '--target', javaTargetDir,
        '--package', 'com.yourcompany.wave1',
        '--strategy', 'static'
}

compileJava.dependsOn compilePli

13.2.3 Build Commands

# Clean build
./gradlew clean build

# Compile PL/I only
./gradlew compilePli

# Run specific program
./gradlew runProgram -PmainClass=com.yourcompany.app.CUSTUPD

# Build WAR for CICS
./gradlew war

# Build JAR for batch
./gradlew batchJar

# Build all waves (multi-module)
./gradlew :wave1:build :wave2:build :wave3:build

# Run tests
./gradlew test

# Generate documentation
./gradlew javadoc

13.3 Maven Integration

13.3.1 Basic Maven Configuration

Complete pom.xml for PLI project:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                             http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.yourcompany</groupId>
    <artifactId>myapp-pli</artifactId>
    <version>1.0.0</version>
    <packaging>war</packaging>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

        <!-- PLI configuration -->
        <pli.compiler.version>26.2.27.RC1</pli.compiler.version>
        <pli.runtime.version>26.2.27.RC1</pli.runtime.version>
        <manifold.version>2.0.0</manifold.version>
    </properties>

    <repositories>
        <repository>
            <id>heirloom-releases</id>
            <url>https://your-artifact-repository/maven</url>
        </repository>
    </repositories>

    <dependencies>
        <!-- PLI Runtime -->
        <dependency>
            <groupId>com.heirloom</groupId>
            <artifactId>pli_runtime2</artifactId>
            <version>${pli.runtime.version}</version>
        </dependency>

        <!-- Manifold (compile-time processor) -->
        <dependency>
            <groupId>com.heirloom</groupId>
            <artifactId>heirloom-manifold</artifactId>
            <version>${manifold.version}</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>systems.manifold</groupId>
            <artifactId>manifold-props-rt</artifactId>
            <version>2024.1.42</version>
        </dependency>

        <!-- Jakarta EE (for CICS) -->
        <dependency>
            <groupId>jakarta.platform</groupId>
            <artifactId>jakarta.jakartaee-api</artifactId>
            <version>10.0.0</version>
            <scope>provided</scope>
        </dependency>

        <!-- JDBC Driver -->
        <dependency>
            <groupId>com.ibm.db2</groupId>
            <artifactId>jcc</artifactId>
            <version>11.5.8.0</version>
        </dependency>

        <!-- Testing -->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>5.10.0</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <!-- Add generated source directory -->
        <plugins>
            <!-- PLI Compiler Plugin -->
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>3.1.1</version>
                <executions>
                    <execution>
                        <id>compile-pli</id>
                        <phase>generate-sources</phase>
                        <goals>
                            <goal>exec</goal>
                        </goals>
                        <configuration>
                            <executable>java</executable>
                            <arguments>
                                <argument>-jar</argument>
                                <argument>${project.basedir}/lib/pli_compiler2-${pli.compiler.version}.jar</argument>
                                <argument>--source</argument>
                                <argument>${project.basedir}/src/main/pli</argument>
                                <argument>--target</argument>
                                <argument>${project.build.directory}/generated-sources/pli</argument>
                                <argument>--package</argument>
                                <argument>com.yourcompany.app</argument>
                                <argument>--strategy</argument>
                                <argument>instance</argument>
                                <argument>--cics</argument>
                                <argument>--sql</argument>
                            </arguments>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

            <!-- Add generated sources to build path -->
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>build-helper-maven-plugin</artifactId>
                <version>3.5.0</version>
                <executions>
                    <execution>
                        <id>add-source</id>
                        <phase>generate-sources</phase>
                        <goals>
                            <goal>add-source</goal>
                        </goals>
                        <configuration>
                            <sources>
                                <source>${project.build.directory}/generated-sources/pli</source>
                            </sources>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

            <!-- Java Compiler with Manifold -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.12.1</version>
                <configuration>
                    <source>11</source>
                    <target>11</target>
                    <compilerArgs>
                        <arg>-Xplugin:Manifold</arg>
                        <arg>--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED</arg>
                        <arg>--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED</arg>
                        <arg>--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED</arg>
                        <arg>--add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED</arg>
                        <arg>--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED</arg>
                        <arg>--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED</arg>
                    </compilerArgs>
                    <fork>true</fork>
                </configuration>
            </plugin>

            <!-- WAR Plugin -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.4.0</version>
                <configuration>
                    <warName>myapp-cics</warName>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

13.3.2 Maven Commands

# Clean and build
mvn clean package

# Compile PL/I only
mvn exec:exec@compile-pli

# Build WAR
mvn clean package

# Run tests
mvn test

# Install to local repository
mvn install

# Deploy to remote repository
mvn deploy

13.4 CI/CD Pipeline Integration

13.4.1 Jenkins Pipeline

Jenkinsfile:

pipeline {
    agent any

    tools {
        jdk 'JDK-11'
        gradle 'Gradle-8'
    }

    environment {
        PLI_COMPILER_JAR = "${WORKSPACE}/lib/pli_compiler2-26.2.27.RC1.jar"
    }

    stages {
        stage('Checkout') {
            steps {
                git branch: 'main', url: 'https://git.yourcompany.com/pli-app.git'
            }
        }

        stage('Compile PL/I') {
            steps {
                sh './gradlew compilePli'
            }
        }

        stage('Build Java') {
            steps {
                sh './gradlew build'
            }
        }

        stage('Test') {
            steps {
                sh './gradlew test'
            }
            post {
                always {
                    junit '**/build/test-results/test/*.xml'
                }
            }
        }

        stage('Package') {
            steps {
                sh './gradlew war'
            }
        }

        stage('Deploy to Dev') {
            when {
                branch 'develop'
            }
            steps {
                sh './deploy-to-dev.sh build/libs/myapp-cics.war'
            }
        }

        stage('Deploy to Production') {
            when {
                branch 'main'
            }
            steps {
                input message: 'Deploy to production?', ok: 'Deploy'
                sh './deploy-to-prod.sh build/libs/myapp-cics.war'
            }
        }
    }

    post {
        success {
            emailext subject: "Build SUCCESS: ${env.JOB_NAME}",
                     body: "Build ${env.BUILD_NUMBER} succeeded",
                     to: 'team@yourcompany.com'
        }
        failure {
            emailext subject: "Build FAILED: ${env.JOB_NAME}",
                     body: "Build ${env.BUILD_NUMBER} failed",
                     to: 'team@yourcompany.com'
        }
    }
}

13.4.2 GitLab CI/CD

.gitlab-ci.yml:

image: gradle:8-jdk11

variables:
  PLI_COMPILER_VERSION: "26.2.27.RC1"

stages:
  - compile
  - build
  - test
  - package
  - deploy

compile-pli:
  stage: compile
  script:
    - ./gradlew compilePli
  artifacts:
    paths:
      - generated/
    expire_in: 1 hour

build-java:
  stage: build
  dependencies:
    - compile-pli
  script:
    - ./gradlew compileJava
  artifacts:
    paths:
      - build/classes/
    expire_in: 1 hour

test:
  stage: test
  dependencies:
    - build-java
  script:
    - ./gradlew test
  artifacts:
    reports:
      junit: build/test-results/test/*.xml

package-war:
  stage: package
  dependencies:
    - build-java
  script:
    - ./gradlew war
  artifacts:
    paths:
      - build/libs/*.war
    expire_in: 1 week

deploy-dev:
  stage: deploy
  only:
    - develop
  script:
    - ./deploy-to-dev.sh build/libs/myapp-cics.war
  environment:
    name: development
    url: https://dev.yourcompany.com/myapp

deploy-prod:
  stage: deploy
  only:
    - main
  when: manual
  script:
    - ./deploy-to-prod.sh build/libs/myapp-cics.war
  environment:
    name: production
    url: https://prod.yourcompany.com/myapp

13.4.3 GitHub Actions

.github/workflows/build.yml:

name: Build and Deploy

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
    - name: Checkout code
      uses: actions/checkout@v4

    - name: Set up JDK 11
      uses: actions/setup-java@v4
      with:
        java-version: '11'
        distribution: 'temurin'

    - name: Cache Gradle packages
      uses: actions/cache@v3
      with:
        path: ~/.gradle/caches
        key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
        restore-keys: ${{ runner.os }}-gradle

    - name: Compile PL/I
      run: ./gradlew compilePli

    - name: Build with Gradle
      run: ./gradlew build

    - name: Run tests
      run: ./gradlew test

    - name: Upload test results
      if: always()
      uses: actions/upload-artifact@v3
      with:
        name: test-results
        path: build/test-results/

    - name: Build WAR
      run: ./gradlew war

    - name: Upload WAR artifact
      uses: actions/upload-artifact@v3
      with:
        name: myapp-war
        path: build/libs/*.war

  deploy-dev:
    needs: build
    if: github.ref == 'refs/heads/develop'
    runs-on: ubuntu-latest

    steps:
    - name: Download WAR
      uses: actions/download-artifact@v3
      with:
        name: myapp-war

    - name: Deploy to Dev
      run: |
        # Your deployment script here
        echo "Deploying to development..."


13.5 Deployment Strategies

13.5.1 CICS Web Application Deployment

Deploy to Payara:

# Deploy WAR to Payara
asadmin deploy --force=true build/libs/myapp-cics.war

# Undeploy
asadmin undeploy myapp-cics

# Redeploy
asadmin redeploy build/libs/myapp-cics.war

Deploy to WildFly:

# Deploy
jboss-cli.sh --connect --command="deploy build/libs/myapp-cics.war"

# Undeploy
jboss-cli.sh --connect --command="undeploy myapp-cics.war"

13.5.2 Batch Application Deployment

Deploy to EBP:

# Copy JAR to EBP classpath
cp build/libs/myapp-batch.jar /opt/ebp/lib/

# Copy JCL files
cp src/main/jcl/*.jcl /opt/ebp/jobs/

# Submit test job
curl -X POST http://localhost:8080/ebp/api/jobs \
  -H "Content-Type: text/plain" \
  -d @/opt/ebp/jobs/TESTJOB.jcl

13.5.3 Docker Deployment

Dockerfile for CICS application:

FROM payara/server-full:6.2024.2-jdk11

# Copy WAR
COPY build/libs/myapp-cics.war /opt/payara/deployments/

# Copy configuration
COPY config/pli.properties /opt/payara/config/

# Expose ports
EXPOSE 8080 4848

# Start Payara
CMD ["asadmin", "start-domain", "--verbose"]

Build and run:

docker build -t myapp-cics:1.0.0 .
docker run -d -p 8080:8080 myapp-cics:1.0.0


13.6 Build Optimization

13.6.1 Incremental Compilation

Gradle automatically handles incremental builds:

task compilePli(type: Exec) {
    // Enable incremental build
    inputs.dir(pliSourceDir)
    outputs.dir(javaTargetDir)

    // Only recompile if PL/I sources changed
    onlyIf {
        !javaTargetDir.exists() ||
        pliSourceDir.listFiles().any {
            it.lastModified() > javaTargetDir.lastModified()
        }
    }
}

13.6.2 Parallel Builds

# Enable parallel execution
./gradlew build --parallel --max-workers=4

# Build multiple waves in parallel
./gradlew :wave1:build :wave2:build :wave3:build --parallel

13.6.3 Build Caching

// Enable build cache in gradle.properties
org.gradle.caching=true

// Configure remote cache
buildCache {
    remote(HttpBuildCache) {
        url = 'https://cache.yourcompany.com/'
        push = true
        credentials {
            username = System.getenv('CACHE_USER')
            password = System.getenv('CACHE_PASSWORD')
        }
    }
}

13.7 Troubleshooting Build Issues

Common Issues

"pli_compiler2.jar not found"

Cause: Compiler JAR not in expected location.

Solution:

ext {
    pliCompilerJar = file("${System.getenv('PLI_COMPILER_HOME')}/pli_compiler2.jar")
}

"Manifold plugin not found"

Cause: Missing Manifold dependency or incorrect configuration.

Solution: - Verify heirloom-manifold is in annotationProcessor dependencies - Check javac exports are configured

"Generated Java files not found"

Cause: PLI compilation failed silently.

Solution:

task compilePli(type: Exec) {
    // Fail build if PLI compilation fails
    ignoreExitValue = false

    // Log output
    standardOutput = System.out
    errorOutput = System.err
}