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:
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:
"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
}