Comprehensive analysis of the QRE (QRE Runtime Environment) framework used by DDEC
Framework size: 1,866 Java files across 9+ modules
The QRE framework is a complete mainframe transformation system built by DXC (formerly CSC) that emulates COBOL, IMS/DLI, VSAM, and batch processing in Java/Spring Boot. The DDEC application depends entirely on this framework.
ddec-qre (1,866 Java files)
├── qre2-parent/ (core QRE framework)
│ ├── qre2-core (data types, base interfaces)
│ ├── qre2-data (database access, SQL)
│ ├── qre2-file (file I/O)
│ ├── qre2-cobol (COBOL language support, 99 programs)
│ ├── qre2-web (web/CICS, Keycloak integration)
│ └── qre2-batch-core (batch processing)
│
├── qre2-mvs-parent/ (mainframe-specific)
│ ├── qre2-ims (IMS/DLI database, terminal management)
│ ├── qre2-batch-korn (batch scripting)
│ ├── qre2-mvs-starter (base configuration)
│ └── qre2-mvs-starter-ims (IMS-specific configuration)
│
└── DDEC application (451+ programs)
├── Uses: com.csc.qre.cobol.lang.CobolFunctions
├── Uses: com.csc.qre.core.datatype.* (all data types)
├── Uses: com.csc.qre.file.disk.* (file I/O)
├── Uses: com.csc.qre.ims.dli.* (database)
└── Extends: AbstractCobolCodeModel (base class)
All QRE data types implement the LegacyData interface. This is the universal abstraction for COBOL data items.
public interface LegacyData {
byte[] getBytes(); // Raw byte representation
void setBytes(byte[]); // Set from raw bytes
int getLength(); // COBOL PIC length
void set(Object value); // Set from Java object
Object get(); // Get as Java object
String display(); // COBOL DISPLAY format
boolean isNumeric(); // COBOL IS NUMERIC test
void clear(); // INITIALIZE equivalent
}
Emulates COBOL PIC X(n) alphanumeric fields.
public interface FixedLengthString extends LegacyData {
String substring(int start, int length);
void setSubstring(int start, int length, String value);
FixedLengthString reference(int offset, int length); // REFERENCE MODIFICATION
void movel(String value); // MOVE with left-justify, space-fill
void mover(String value); // MOVE with right-justify
}
Key behaviors:
Emulates COBOL PIC S9(n)V9(m) COMP-3 packed decimal fields.
public interface PackedDecimal extends LegacyData {
BigDecimal toBigDecimal();
void set(BigDecimal value);
int getScale(); // Decimal places
int getPrecision(); // Total digits
boolean isSigned();
}
Storage: Each byte holds 2 decimal digits (nibbles), last nibble is sign (C=positive, D=negative, F=unsigned).
Emulates COBOL PIC S9(n)V9(m) DISPLAY zoned decimal fields.
public interface ZonedDecimal extends LegacyData {
BigDecimal toBigDecimal();
int getScale();
int getPrecision();
boolean isBlank(); // All spaces = zero
}
Storage: Each digit occupies one byte. Zone bits (high nibble) are 0xF for all digits except last, where sign is encoded.
Emulates COBOL PIC S9(n) COMP / COMP-4 binary fields.
public interface BinaryItem extends LegacyData {
long toLong();
void set(long value);
int getByteLength(); // 2, 4, or 8 bytes
}
Emulates COBOL group items (record structures).
public interface DataGroup extends LegacyData {
LegacyData getField(String name);
List<LegacyData> getFields();
void redefines(DataGroup other); // REDEFINES clause
}
Provides COBOL intrinsic function equivalents:
String Operations:
inspect(source, tallyFor, replacing) - INSPECT TALLYING/REPLACINGstring(sources[], delimitedBy[], into) - STRING statementunstring(source, delimitedBy[], into[]) - UNSTRING statementmove(source, destination) - MOVE with type conversionNumeric Operations:
add(a, b, result) - ADD with ON SIZE ERRORsubtract(a, b, result) - SUBTRACTmultiply(a, b, result) - MULTIPLYdivide(a, b, quotient, remainder) - DIVIDE with REMAINDERcompute(expression, result) - COMPUTEDate Operations:
integerOfDate(date) - INTEGER-OF-DATE functiondateOfInteger(integer) - DATE-OF-INTEGER functioncurrentDate() - CURRENT-DATE functionwhenCompiled() - WHEN-COMPILED functionControl Flow:
exitProgram() - EXIT PROGRAM (throws ProgramExitException)stopRun() - STOP RUN (throws ProgramTerminateException)goBack() - GOBACK statementdisplay(text) - DISPLAY statement (logs to output)accept(field) - ACCEPT statement (reads from SYSIN)Table Operations:
search(table, atEnd, whenCondition) - SEARCH statementsearchAll(table, atEnd, whenCondition) - SEARCH ALL (binary search)All converted COBOL programs extend this class:
public abstract class AbstractCobolCodeModel implements CodeModel {
// Working storage (instance variables)
protected int tallyRegister;
// Program execution
public abstract void execute();
// Subroutine support
protected void callProgram(String programName, LegacyData... params);
protected void cancelProgram(String programName);
// File operations
protected void openInput(CobolFile file);
protected void openOutput(CobolFile file);
protected void read(CobolFile file, LegacyData... into);
protected void write(CobolFile file, FixedLengthString record);
protected void close(CobolFile file);
// Error handling
protected void exitProgram();
protected void stopRun();
protected void goBack();
// Lifecycle
public void dispose();
}
// COBOL: CALL 'PGMB' USING WS-PARM1 WS-PARM2
callProgram("PGMB", wsParm1, wsParm2);
// Implementation:
// 1. Look up PGMB in program registry (program_mapping.properties)
// 2. Instantiate or retrieve from ProgramCache
// 3. Set parameters via LegacyData references
// 4. Call execute()
// 5. Return control to caller
Emulates COBOL sequential file processing (QSAM/BSAM).
public interface SequentialDiskFile extends CobolFile {
void openInput();
void openOutput();
void openExtend(); // OPEN EXTEND (append)
void close();
int read(LegacyData... receivingFields);
void write(FixedLengthString record);
int getStatus(); // FILE STATUS
}
File Status Codes:
00 = Success10 = End of file (AT END)30 = Permanent I/O error35 = File not found (OPEN INPUT)46 = READ after end of fileEmulates COBOL VSAM (Virtual Storage Access Method) indexed files.
public interface IndexedDiskFile extends CobolFile {
void setAccessMode(AccessMode accessMode); // SEQUENTIAL, RANDOM, DYNAMIC
boolean isForUpdate();
void setUpdate(boolean forUpdate);
boolean isGeneric(); // Partial key matching
void setGeneric(boolean genericKey);
void start(LegacyData... receivingDatas);
void start(ComparisonOperator operator, LegacyData... receivingDatas);
void readNext();
void rewrite(FixedLengthString record);
LegacyData delete();
LegacyData delete(LegacyData recordID);
}
VSAM Operations Emulated:
High-performance reader for flat files with multiple implementations:
BufferedFlatFileReader - Standard buffered I/OBisFlatFileReader - Using BufferedInputStreamDirectByteBufferFlatFileReader - Direct ByteBuffer (off-heap)MappedByteBufferFlatFileReader - Memory-mapped file (fastest)| Function | Description | SQL Equivalent |
|---|---|---|
| GU | Get Unique | SELECT TOP 1 WHERE PK = value |
| GN | Get Next | SELECT TOP 1 WHERE PK > current ORDER BY PK |
| GNP | Get Next within Parent | SELECT TOP 1 WHERE FK = parent AND PK > current |
| GHU | Get Hold Unique | SELECT ... WITH (XLOCK, HOLDLOCK, ROWLOCK, NOWAIT) |
| GHN | Get Hold Next | Same with XLOCK |
| ISRT | Insert | INSERT INTO table (...) VALUES (...) |
| REPL | Replace | UPDATE table SET ... WHERE PK = value |
| DLET | Delete | DELETE FROM table WHERE PK = value |
public abstract class PcbMask {
String segmentName; // 8 bytes - segment/table name
String reservedId; // 2 bytes - "DB" for database
String statusCode; // 2 bytes - result status
byte segmentLevel; // 1 byte - hierarchy level
}
Status Codes:
"" (spaces) = SuccessGE = Segment not foundGB = End of databaseII = Duplicate key on insertDA = Data errorQualified SSAs provide WHERE clause equivalents:
SEGNAME (FIELD = VALUE) -- Simple equality
SEGNAME (FIELD >= VALUE) -- Range
SEGNAME (FIELD1 = VAL1 & FIELD2 = VAL2) -- AND
The DdecCoreDao class is the critical bridge between IMS DLI calls and SQL Server. Key implementation details:
INFORMATION_SCHEMA.COLUMNS at runtime to discover table structureConcurrentHashMapCaseUtils.toCamelCase(columnName, false, '_')BILLING_EXTRACT_DDEC3, BILLING_EXTRACT_DDEC5WITH(XLOCK, HOLDLOCK, ROWLOCK, NOWAIT)@Configuration
@EnableResourceLock
@EnableQre({
QreCoreConfiguration.class,
BasicServiceConfiguration.class,
})
@EnableJdbc({
AppDataConfiguration.class,
EmbeddedSqlConfiguration.class,
})
@Import({
BasicCobolConfiguration.class,
BasicFileConfiguration.class,
MvsBatchConfiguration.class,
MvsWebConfiguration.class
})
public class MvsConfiguration { }
@Configuration
@Import(MvsConfiguration.class)
@EnableIms
public class MvsImsConfiguration { }
Adds: DLI database access, IMS transaction processing, PCB management, terminal supplier factories
@Import(BasicWebSecurityKeycloakConfiguration.class)
public @interface EnableKeycloak { }
Provides: Keycloak adapter, OAuth2/OIDC, Spring Security integration, RBAC
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface LegacyProgram {
String value(); // Legacy program name
String path() default ""; // Optional library path
}
At compile time, annotation processing generates program_mapping.properties mapping program names to Java classes.
| QRE Component | ASP.NET Core Replacement | Technology |
|---|---|---|
| CobolFunctions | Static utility classes | C# static methods |
| FixedLengthString/PackedDecimal | Custom struct/class | Custom types |
| COBOL Programs (99 files) | Service classes | MediatR handlers or direct classes |
| IMS/DLI | Database access layer | EF Core + stored procedures |
| PCB Masks | Data models/records | C# records/classes |
| Terminal Management | Session management | Distributed cache (Redis) |
| File I/O | System.IO abstraction | Custom IFileService |
| Spring Configuration | Dependency Injection | Microsoft.Extensions.DependencyInjection |
| @LegacyProgram | Service registration | Custom attribute + reflection |
// FixedLengthString
public class FixedLengthString : IEquatable<FixedLengthString>
{
private readonly string value;
private readonly int length;
public FixedLengthString(int length, string? initialValue = null)
{
this.length = length;
this.value = (initialValue ?? "").PadRight(length).Substring(0, length);
}
public string Substring(int start, int len)
=> value.Substring(start, len).TrimEnd();
public void SetSubstring(int start, int len, string val)
=> // Reconstruct with replacement
}
// PackedDecimal
public class PackedDecimal
{
private byte[] packedBytes;
private int scale;
public void Set(decimal value)
{
var digits = value.ToString("F" + scale).Replace(".", "");
// Pack nibbles with sign
}
public decimal ToDecimal()
{
// Unpack nibbles to decimal
}
}
// DLI Functions mapping
public enum DliFunction
{
GU = 1, // Get Unique
GN = 2, // Get Next
ISRT = 3, // Insert
REPL = 4, // Replace
DLET = 5 // Delete
}
// In ASP.NET Core, we replace ALL of this with EF Core:
// GU -> dbContext.SDD3Units.FirstOrDefault(u => u.UnitNumber == unitNbr)
// GN -> dbContext.SDD3Units.Where(u => u.UnitNumber > current).OrderBy(u => u.UnitNumber).First()
// ISRT -> dbContext.SDD3Units.Add(entity); dbContext.SaveChanges()
// REPL -> entity.Property = newValue; dbContext.SaveChanges()
// DLET -> dbContext.SDD3Units.Remove(entity); dbContext.SaveChanges()
// Program.cs / Startup equivalent
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
// Database
services.AddDbContext<DdecDbContext>(
opt => opt.UseSqlServer(Configuration.GetConnectionString("Ddec")));
// Security (Keycloak replacement)
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddKeycloakOpenIdConnect("keycloak", options => { ... });
// Legacy program registry (if needed for gradual migration)
services.RegisterLegacyPrograms(typeof(Program).Assembly);
}
}
// LegacyProgram attribute equivalent
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class LegacyProgramAttribute : Attribute
{
public string Name { get; }
public string? Path { get; set; }
public LegacyProgramAttribute(string name) => Name = name;
}
public static class CobolFunctions
{
public static void Initialize(ILegacyData data) => data.Clear();
public static int InspectTally(string source, string pattern)
{
var regex = new Regex(Regex.Escape(pattern));
return regex.Matches(source).Count;
}
public static int IntegerOfDate(int dateInt)
{
int year = dateInt / 10000;
int month = (dateInt % 10000) / 100;
int day = dateInt % 100;
var date = new DateOnly(year, month, day);
var cobolEpoch = new DateOnly(1600, 12, 31);
return date.DayNumber - cobolEpoch.DayNumber;
}
}
| Phase | Work | Effort |
|---|---|---|
| 1 - Foundation | Data types (FixedLengthString, PackedDecimal, ZonedDecimal) | 4-6 weeks |
| 2 - COBOL Functions | 50+ intrinsic functions | 3-4 weeks |
| 3 - IMS/DLI Support | EF Core + stored procedures | 4-6 weeks |
| 4 - Program Migration | Convert 99+ programs to C# services | 6-8 weeks |
| 5 - Integration | Web API, session, security | 3-4 weeks |
| Total | Full feature parity | 20-28 weeks |
Key Success Factors:
The QRE framework includes a lot of infrastructure we can skip:
What we DO need: