บทนำเชิงสถาปัตยกรรม (Conceptual Narrative & The Composite Architecture Challenge):
ในโลกความเป็นจริงของระบบ Enterprise ระดับ Production เราแทบไม่เคยสร้างรายงานที่มีเพียงฟีเจอร์เดี่ยวๆ แยกส่วนกัน สิ่งที่สถาปนิกรายงานต้องเผชิญคือ Composite Multi-Tier Document เช่น "รายงานตรวจสอบผลการดำเนินงานและความเสี่ยงระดับองค์กร (Executive Risk & Performance Audit Dossier)" ที่ต้องมี:
1) Group Hierarchy แยกตามแผนกหรือภูมิภาค พร้อมควบคุมการขึ้นหน้าใหม่ด้วย minHeightToStartNewPage
2) Nested Subreports ฝังในระดับ Detail เพื่อดึงรายการธุรกรรมที่แยกอิสระ พร้อมส่งยอดรวมกลับมาด้วย Two-way Return Values
3) Dynamic Crosstab Matrix ฝังอยู่ใน Group Header หรือ Group Footer เพื่อสรุปสถิติแบบ Pivot Table 2 มิติ (ไตรมาส x ระดับความเสี่ยง)
4) Centralized JRTX Tokens & Conditional Formatting ควบคุมสี ฟอนต์ และการแจ้งเตือนยอดเงินผิดปกติทั่วทั้งเอกสารจากไฟล์ภายนอก
หากปราศจากความเข้าใจว่า JRVerticalFiller, CrosstabBucketingService, และ Child Subreport Engines มีลำดับการแบ่ง Memory และรอบวงจรชีวิต (Evaluation Cycles) สัมพันธ์กันอย่างไร ระบบจะพังทลายทันทีด้วยอาการ Evaluation Timing Collisions, Variable Bleeding หรือ Heap Memory Exhaustion บทเรียน Capstone นี้คือบททดสอบเพื่อหลอมรวมทุกกลไกของ Level 2 ให้เป็นหนึ่งเดียว
CrosstabBucketingService เพื่อคำนวณ Matrix ก่อน จากนั้นจึง Spawn Child JRVerticalFiller ของ Subreport โดยลำดับการวาด Band และการจัดสรรความสูงจะผูกกันเป็นทอดๆ
<returnValue> มาอัปเดตลง Group Accumulator ใน Master → (3) สะสมต่อเข้า Master Grand Total ใน Summary Band โดยตัวแปรที่รับค่าต้องตั้ง calculation="System"
new JRBeanCollectionDataSource(...) ช่วยป้องกันไม่ให้เกิด Data Source Exhaustion เมื่อ Group ถัดไปถูกประมวลผล
.jrtx) ข้ามทั้ง Master และ Subreport เพื่อให้ทั้งเอกสาร รวมถึงส่วนของ Crosstab Cells และ Alert Badges มี Visual Language เดียวกัน พร้อมสืบทอดกฎ Conditional Formatting โดยไม่มี Inline Duplication
แผนภาพแสดงลำดับการเชื่อมต่อระหว่าง Group State Machine, Subreport Child Engine, Crosstab Pivot Engine และ JRTX Style Resolution:
ลำดับการทำงานในหน่วยความจำ JVM (Composite Execution Order):
.jrtx และลงทะเบียน Design Tokens ลงใน Context RegistryGroup HeaderresetType="Group"เมทริกซ์ความเสี่ยงและจุดพังทลายบน Production (Production Hazard Matrix):
| จุดเชื่อมโยง | ความเสี่ยงร้ายแรง (Hazard) | กลไกป้องกัน (Architectural Defense) |
|---|---|---|
| Crosstab ใน Group | หน่วยความจำบวมตามจำนวนกลุ่ม | กรองข้อมูลล่วงหน้าจาก SQL / ใช้ Virtualizer |
| Return Value ใน Group | ตัวเลขสะสมไหลข้ามกลุ่ม (Bleeding) | ตั้งตัวแปร Master เป็น resetType="Group" |
| Subreport ใน Detail | Connection Pool Exhaustion | ส่ง Sub-Collection Java DataSource แทน JDBC |
| Style ข้าม Subreport | ฟอนต์และสีเพี้ยนระหว่างแม่ลูก | ประกาศ <template> เดียวกันในไฟล์ลูก |
java.lang.OutOfMemoryError: Java heap space ทันที
ตัวอย่างโครงสร้าง JRXML 7.0.x ที่ผสาน Grouping, Crosstab, Subreport Return Values และ JRTX Templates เข้าด้วยกัน:
<!-- Composite Enterprise Template (7.0.x Standard) -->
<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports"
name="CompositeEnterpriseDossier" pageWidth="595" pageHeight="842"
columnWidth="555" leftMargin="20" rightMargin="20"
topMargin="20" bottomMargin="20">
<!-- 1. Shared Design Tokens -->
<template><![CDATA["styles/enterprise_tokens.jrtx"]]></template>
<!-- 2. Multi-tier Accumulators -->
<variable name="GROUP_TOTAL" calculation="System" class="java.math.BigDecimal" resetType="Group" resetGroup="DeptGroup">
<initialValueExpression><![CDATA[BigDecimal.ZERO]]></initialValueExpression>
</variable>
<group name="DeptGroup" minHeightToStartNewPage="200">
<expression><![CDATA[$F{department}]]></expression>
<groupHeader>
<band height="120">
<!-- 3. Dynamic Matrix Inside Group -->
<element kind="crosstab" x="0" y="30" width="555" height="80">
<rowGroup name="Tier" width="100">
<bucket class="java.lang.String"><expression><![CDATA[$F{tier}]]></expression></bucket>
</rowGroup>
<columnGroup name="Quarter" height="20">
<bucket class="java.lang.String"><expression><![CDATA[$F{quarter}]]></expression></bucket>
</columnGroup>
<measure name="MetricSum" class="java.math.BigDecimal" calculation="Sum">
<expression><![CDATA[$F{metricValue}]]></expression>
</measure>
</element>
</band>
</groupHeader>
<groupFooter>
<band height="30">
<element kind="textField" style="HeaderStyle" x="355" y="5" width="200" height="20">
<expression><![CDATA[$V{GROUP_TOTAL}]]></expression>
</element>
</band>
</groupFooter>
</group>
</jasperReport>
ข้อกำหนดทางเทคนิค (Full-Coverage 100%):
1. ประกาศนำเข้า Style Template ผ่านแท็ก <template> ชี้ไปยัง "styles/enterprise_tokens.jrtx"
2. กำหนดกลุ่ม <group name="DivisionGroup" minHeightToStartNewPage="180"> ป้องกันปัญหา Orphan Header
3. ฝัง <element kind="crosstab"> ภายใน Group Header เพื่อสรุปยอดแบบ Matrix รายแผนก
4. ใช้แท็กสมัยใหม่ <element kind="textField"> ตามมาตรฐาน 7.0.x Unified Element Model
ข้อกำหนดทางเทคนิค (Full-Coverage 100%):
1. ประกาศตัวแปร MASTER_AUDIT_TOTAL ชนิด BigDecimal โดยตั้ง calculation="System"
2. กำหนด <element kind="subreport"> ใน Detail Band ส่งข้อมูลผ่าน JRBeanCollectionDataSource
3. เชื่อมต่อ <returnValue fromVariable="CHILD_SUM" toVariable="MASTER_AUDIT_TOTAL" calculation="Sum"/>
4. กำหนด <style name="AlertStyle"> พร้อม <conditionalStyle> เปลี่ยนสีเป็นสีแดงเมื่อยอดเงินติดลบ
แบบทดสอบ 15 ข้อเชิงลึกระดับ Master วัดความเข้าใจเรื่องสถาปัตยกรรมองค์รวมของ Level 2: