1. 为什么ABAP开发者需要表达式日志记录
在SAP ABAP开发中,调试复杂的业务逻辑时,我们经常需要追踪表达式的执行过程和中间结果。想象一下你正在处理一个包含多层嵌套的财务计算公式,或者一个涉及多个表关联的数据转换逻辑。传统调试方式要么需要设置断点逐步执行,要么在代码中插入大量WRITE语句输出中间值 - 这两种方法都效率低下且破坏代码整洁性。
CL_DEMO_OUTPUT类提供了一种优雅的解决方案,它就像给ABAP表达式装上了行车记录仪,能够在不中断程序执行的情况下,完整记录表达式的计算过程和结果。这种方法特别适合以下场景:
- 复杂条件判断的逻辑验证
- 数据转换过程的中间值检查
- 性能优化时的表达式评估次数统计
- 生产环境问题复现时的数据追踪
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. CL_DEMO_OUTPUT的核心功能解析
2.1 基本输出机制
CL_DEMO_OUTPUT是SAP标准库中专门用于演示输出的工具类,它提供了一系列静态方法来实现格式化输出。最常用的三个方法是:
abap复制CLASS-METHODS:
BEGIN_SECTION IMPORTING title TYPE string,
WRITE_DATA IMPORTING data TYPE any,
DISPLAY.
实际使用时,我们可以这样构建一个简单的日志记录:
abap复制DATA(lv_result) = 1 + 2 * 3.
CL_DEMO_OUTPUT=>BEGIN_SECTION( '表达式计算示例' ).
CL_DEMO_OUTPUT=>WRITE_DATA( |初始表达式: 1 + 2 * 3| ).
CL_DEMO_OUTPUT=>WRITE_DATA( |中间结果: 2 * 3 = { 2 * 3 }| ).
CL_DEMO_OUTPUT=>WRITE_DATA( |最终结果: 1 + 6 = { lv_result }| ).
CL_DEMO_OUTPUT=>DISPLAY( ).
2.2 高级特性与应用
除了基本输出,CL_DEMO_OUTPUT还支持:
- 结构化数据展示:自动格式化内表、结构体等复杂类型
- 多级章节嵌套:通过多次调用BEGIN_SECTION实现层次化输出
- 条件输出控制:结合IF条件实现选择性日志记录
- 性能计时功能:可以记录代码块的执行时间
一个典型的高级应用示例:
abap复制CL_DEMO_OUTPUT=>BEGIN_SECTION( '采购订单处理' ).
" 模拟从数据库获取数据
SELECT * FROM ekko INTO TABLE @DATA(lt_orders) UP TO 10 ROWS.
CL_DEMO_OUTPUT=>BEGIN_SECTION( '原始订单数据' ).
CL_DEMO_OUTPUT=>WRITE_DATA( lt_orders ).
CL_DEMO_OUTPUT=>END_SECTION( ).
" 数据处理逻辑
DATA(lt_processed) = VALUE #( FOR order IN lt_orders
( ebeln = order-ebeln
netwr = order-netwr * '0.9' ) ).
CL_DEMO_OUTPUT=>BEGIN_SECTION( '处理后数据' ).
CL_DEMO_OUTPUT=>WRITE_DATA( lt_processed ).
CL_DEMO_OUTPUT=>END_SECTION( ).
CL_DEMO_OUTPUT=>DISPLAY( ).
3. 实现表达式日志记录的具体技巧
3.1 基本表达式记录模式
要实现表达式日志记录,我们可以创建一个简单的工具方法:
abap复制METHODS log_expression
IMPORTING
iv_expression TYPE string
iv_result TYPE any.
METHOD log_expression.
CL_DEMO_OUTPUT=>WRITE_DATA( |{ iv_expression } = { iv_result }| ).
ENDMETHOD.
使用时只需要在关键表达式后调用:
abap复制DATA(lv_discount) = 0.85.
DATA(lv_price) = 100 * lv_discount.
log_expression(
iv_expression = '100 * 0.85 (折扣后价格)'
iv_result = lv_price ).
3.2 条件表达式调试技巧
对于复杂的条件表达式,可以拆解记录每个部分的评估结果:
abap复制DATA(lv_age) = 25.
DATA(lv_member) = abap_true.
IF ( lv_age > 18 AND lv_age < 60 ) AND lv_member = abap_true.
" 业务逻辑
ENDIF.
" 调试记录
CL_DEMO_OUTPUT=>BEGIN_SECTION( '条件表达式分析' ).
log_expression( iv_expression = 'lv_age > 18' iv_result = COND #( WHEN lv_age > 18 THEN '真' ELSE '假' ) ).
log_expression( iv_expression = 'lv_age < 60' iv_result = COND #( WHEN lv_age < 60 THEN '真' ELSE '假' ) ).
log_expression( iv_expression = 'lv_member = abap_true' iv_result = COND #( WHEN lv_member = abap_true THEN '真' ELSE '假' ) ).
log_expression( iv_expression = '整体条件结果' iv_result = COND #( WHEN ( lv_age > 18 AND lv_age < 60 ) AND lv_member = abap_true THEN '真' ELSE '假' ) ).
CL_DEMO_OUTPUT=>DISPLAY( ).
3.3 内表操作表达式记录
处理内表时,可以记录关键转换步骤:
abap复制DATA: lt_sales TYPE TABLE OF vbak,
lt_summary TYPE TABLE OF ty_summary.
" 模拟数据获取
SELECT * FROM vbak INTO TABLE lt_sales UP TO 20 ROWS.
" 数据处理
lt_summary = VALUE #(
FOR GROUPS group OF sales IN lt_sales
GROUP BY ( sales_vkorg = sales-vkorg )
( sales_vkorg = group-sales_vkorg
total = REDUCE #(
INIT sum = 0
FOR sale IN GROUP group
NEXT sum = sum + sale-netwr ) ) ).
" 记录转换过程
CL_DEMO_OUTPUT=>BEGIN_SECTION( '内表分组汇总' ).
CL_DEMO_OUTPUT=>WRITE_DATA( |原始销售订单数: { lines( lt_sales ) }| ).
CL_DEMO_OUTPUT=>WRITE_DATA( |按销售组织分组后组数: { lines( lt_summary ) }| ).
CL_DEMO_OUTPUT=>BEGIN_SECTION( '分组汇总结果' ).
CL_DEMO_OUTPUT=>WRITE_DATA( lt_summary ).
CL_DEMO_OUTPUT=>DISPLAY( ).
4. 高级应用与性能优化
4.1 生产环境下的日志控制
在生产环境中,我们需要控制日志的输出量。可以通过自定义标志来控制:
abap复制CLASS lcl_app DEFINITION.
PUBLIC SECTION.
CLASS-DATA gv_debug_mode TYPE abap_bool VALUE abap_false.
CLASS-METHODS set_debug_mode IMPORTING iv_active TYPE abap_bool.
ENDCLASS.
METHODS log_expression.
IF gv_debug_mode = abap_true.
CL_DEMO_OUTPUT=>WRITE_DATA( |{ iv_expression } = { iv_result }| ).
ENDIF.
ENDMETHOD.
4.2 性能敏感的表达式记录
对于性能敏感的代码,可以使用条件编译或只在错误情况下记录:
abap复制METHOD calculate_tax.
DATA(lv_tax) = iv_amount * iv_rate.
" 只在调试模式或计算异常时记录
IF lcl_app=>gv_debug_mode = abap_true OR lv_tax < 0.
log_expression(
iv_expression = |{ iv_amount } * { iv_rate } (税率计算)|
iv_result = lv_tax ).
ENDIF.
ENDMETHOD.
4.3 与SAP标准日志的集成
可以将CL_DEMO_OUTPUT与SAP应用日志集成:
abap复制METHOD log_to_application_log.
TRY.
CL_DEMO_OUTPUT=>BEGIN_SECTION( iv_title ).
LOOP AT it_data ASSIGNING FIELD-SYMBOL(<line>).
CL_DEMO_OUTPUT=>WRITE_DATA( <line> ).
ENDLOOP.
DATA(lt_output) = CL_DEMO_OUTPUT=>GET( ).
" 写入应用日志
DATA(lo_log) = cl_application_log=>create( ).
lo_log->add_text( iv_text = lt_output ).
lo_log->save( ).
CATCH cx_root INTO DATA(lx_error).
" 错误处理
ENDTRY.
ENDMETHOD.
5. 实际案例:采购订单审批流程调试
5.1 场景描述
假设我们需要调试一个复杂的采购订单审批流程,其中包含多级条件判断和金额计算。使用表达式日志记录可以帮助我们快速定位问题。
5.2 关键表达式记录实现
abap复制METHOD process_purchase_order.
CL_DEMO_OUTPUT=>BEGIN_SECTION( '采购订单审批流程' ).
" 1. 获取订单数据
DATA(ls_order) = get_order_details( iv_ebeln ).
log_expression( iv_expression = '获取订单基本数据' iv_result = |{ ls_order-ebeln } - { ls_order-bukrs }| ).
" 2. 计算订单总金额
DATA(lv_net_value) = calculate_net_value( ls_order ).
log_expression( iv_expression = '订单净价值计算' iv_result = lv_net_value ).
" 3. 确定审批级别
DATA(lv_approval_level) = get_approval_level(
iv_amount = lv_net_value
iv_werks = ls_order-werks
iv_ekgrp = ls_order-ekgrp ).
log_expression(
iv_expression = |审批级别确定(金额={ lv_net_value },工厂={ ls_order-werks },采购组={ ls_order-ekgrp })|
iv_result = lv_approval_level ).
" 4. 执行审批检查
DATA(lv_approved) = check_approval(
iv_ebeln = ls_order-ebeln
iv_level = lv_approval_level ).
log_expression(
iv_expression = '最终审批结果'
iv_result = COND #( WHEN lv_approved THEN '通过' ELSE '拒绝' ) ).
CL_DEMO_OUTPUT=>DISPLAY( ).
ENDMETHOD.
5.3 输出结果分析
执行上述代码后,CL_DEMO_OUTPUT会生成清晰的审批流程日志:
code复制采购订单审批流程
--------------------------------
1. 获取订单基本数据 = 4500000123 - 1000
2. 订单净价值计算 = 12500.50
3. 审批级别确定(金额=12500.50,工厂=1000,采购组=P01) = 2
4. 最终审批结果 = 通过
这种结构化的输出使得调试过程变得非常直观,特别是当审批逻辑复杂时,可以快速定位是哪个环节的计算或判断出现了问题。
6. 常见问题与解决方案
6.1 性能影响评估
虽然CL_DEMO_OUTPUT提供了便利的日志记录功能,但在性能敏感的场景中需要注意:
-
内存消耗:大量日志记录会占用应用服务器内存
- 解决方案:在生产环境中关闭非必要日志,或限制日志大小
-
I/O操作:DISPLAY方法会触发屏幕输出
- 替代方案:使用GET方法获取日志内容,再写入数据库或文件
性能测试示例:
abap复制METHOD test_performance.
DATA(lv_start) = utclong_current( ).
DO 1000 TIMES.
DATA(lv_temp) = sy-index * 2.
" 注释掉日志记录以比较性能差异
" log_expression( iv_expression = '临时计算' iv_result = lv_temp ).
ENDDO.
DATA(lv_end) = utclong_current( ).
DATA(lv_duration) = cl_abap_tstmp=>subtract(
tstmp1 = lv_end
tstmp2 = lv_start ).
WRITE: / '执行耗时:', lv_duration, '微秒'.
ENDMETHOD.
6.2 日志内容过长处理
当处理大量数据时,日志输出可能会变得非常长。解决方法包括:
- 分页显示:将日志分成多个部分显示
- 关键摘要:只记录统计信息和异常情况
- 条件过滤:只记录满足特定条件的数据
示例实现:
abap复制METHOD process_large_data.
CL_DEMO_OUTPUT=>BEGIN_SECTION( '大数据处理摘要' ).
SELECT * FROM bkpf INTO TABLE @DATA(lt_accounting)
WHERE budat BETWEEN @iv_date_from AND @iv_date_up_to.
" 只记录统计信息
CL_DEMO_OUTPUT=>WRITE_DATA( |处理会计凭证数量: { lines( lt_accounting ) }| ).
" 只记录金额异常的凭证
LOOP AT lt_accounting ASSIGNING FIELD-SYMBOL(<doc>)
WHERE dmbtr > 1000000.
CL_DEMO_OUTPUT=>WRITE_DATA( |大额凭证: { <doc>-belnr } 金额: { <doc>-dmbtr }| ).
ENDLOOP.
CL_DEMO_OUTPUT=>DISPLAY( ).
ENDMETHOD.
6.3 与ABAP调试器的协同使用
CL_DEMO_OUTPUT可以与标准ABAP调试器配合使用,提供更全面的调试体验:
- 断点前准备:在关键断点前记录表达式状态
- 变量变化追踪:记录循环中变量的变化过程
- 条件断点增强:在条件断点触发时记录上下文信息
协同使用示例:
abap复制METHOD debug_complex_logic.
DATA: lv_counter TYPE i VALUE 0,
lv_total TYPE p DECIMALS 2 VALUE 0.
CL_DEMO_OUTPUT=>BEGIN_SECTION( '循环处理跟踪' ).
LOOP AT it_data ASSIGNING FIELD-SYMBOL(<row>).
lv_counter = lv_counter + 1.
lv_total = lv_total + <row>-amount.
" 在调试时可以设置条件断点,如 lv_counter = 5
" 断点触发时可以看到之前的处理记录
log_expression(
iv_expression = |第{ lv_counter }次循环累计|
iv_result = lv_total ).
ENDLOOP.
CL_DEMO_OUTPUT=>DISPLAY( ).
ENDMETHOD.
7. 最佳实践与经验分享
7.1 日志记录的分级策略
根据不同的开发阶段和运行环境,建议采用不同的日志级别:
- 开发阶段:详细记录所有关键表达式
- 测试阶段:记录主要业务流程和异常情况
- 生产环境:只记录错误和警告信息
实现示例:
abap复制CLASS lcl_logger DEFINITION.
PUBLIC SECTION.
TYPES: BEGIN OF ty_log_level,
debug TYPE i VALUE 1,
info TYPE i VALUE 2,
warn TYPE i VALUE 3,
error TYPE i VALUE 4,
END OF ty_log_level.
CLASS-METHODS log
IMPORTING
iv_message TYPE string
iv_level TYPE i DEFAULT ty_log_level-info.
ENDCLASS.
METHOD log.
CASE iv_level.
WHEN ty_log_level-debug.
IF gv_debug_mode = abap_true.
CL_DEMO_OUTPUT=>WRITE_DATA( |DEBUG: { iv_message }| ).
ENDIF.
WHEN ty_log_level-info.
CL_DEMO_OUTPUT=>WRITE_DATA( |INFO: { iv_message }| ).
" 其他级别处理...
ENDCASE.
ENDMETHOD.
7.2 表达式记录的命名规范
为了使日志更易读,建议采用一致的命名规范:
- 变量引用:直接使用变量名,如
lv_amount - 计算表达式:描述计算逻辑,如
净价 = 总价 - 折扣 - 条件判断:说明判断内容,如
金额 > 阈值 ?
好的命名示例:
abap复制log_expression(
iv_expression = '折扣后价格 = 原价 * (1 - 折扣率)'
iv_result = lv_final_price ).
log_expression(
iv_expression = 'VIP客户且金额>10000 ?'
iv_result = COND #( WHEN is_vip = abap_true AND lv_amount > 10000
THEN '符合条件' ELSE '不符合' ) ).
7.3 团队协作中的日志约定
在团队开发中,建议制定统一的日志约定:
- 模块标识:每个模块使用特定前缀,如
[FI]表示财务模块 - 严重程度:使用图标或标签表示不同严重程度
- 时间戳:重要操作记录执行时间
- 上下文信息:包含用户、事务码等环境信息
团队日志示例:
abap复制METHOD process_payment.
DATA(lv_timestamp) = |{ sy-datum } { sy-uzeit }|.
CL_DEMO_OUTPUT=>WRITE_DATA( |[FI-PAY] { lv_timestamp } 用户: { sy-uname }| ).
CL_DEMO_OUTPUT=>WRITE_DATA( |[FI-PAY] 付款处理开始, 单据: { iv_document }| ).
" 业务逻辑处理...
IF lv_success = abap_true.
CL_DEMO_OUTPUT=>WRITE_DATA( |[FI-PAY] SUCCESS 付款完成, 金额: { lv_amount }| ).
ELSE.
CL_DEMO_OUTPUT=>WRITE_DATA( |[FI-PAY] ERROR 付款失败: { lv_error_message }| ).
ENDIF.
CL_DEMO_OUTPUT=>DISPLAY( ).
ENDMETHOD.
8. 替代方案与工具比较
8.1 与WRITE语句的比较
传统WRITE语句的局限性:
- 只能输出到特定位置(屏幕、列表等)
- 格式控制能力有限
- 无法轻松收集所有输出内容
CL_DEMO_OUTPUT优势:
- 集中管理所有输出内容
- 支持结构化数据显示
- 可以获取输出内容进行后续处理
8.2 与应用日志(Application Log)的对比
应用日志更适合:
- 生产环境问题追踪
- 长期存储的日志记录
- 系统管理员查看的日志
CL_DEMO_OUTPUT更适合:
- 开发调试过程中的临时记录
- 复杂逻辑的逐步验证
- 需要即时可视化查看的场景
8.3 与SLG1事务码日志的集成方案
对于需要长期保存的重要调试信息,可以将CL_DEMO_OUTPUT与SLG1日志集成:
abap复制METHOD log_to_slg1.
TRY.
" 准备CL_DEMO_OUTPUT内容
CL_DEMO_OUTPUT=>BEGIN_SECTION( iv_title ).
LOOP AT it_data ASSIGNING FIELD-SYMBOL(<line>).
CL_DEMO_OUTPUT=>WRITE_DATA( <line> ).
ENDLOOP.
DATA(lt_output) = CL_DEMO_OUTPUT=>GET( ).
" 创建SLG1日志
DATA: ls_header TYPE bal_s_log,
lt_handle TYPE bal_t_logh.
ls_header-object = iv_object.
ls_header-subobject = iv_subobject.
ls_header-extnumber = iv_extnumber.
CALL FUNCTION 'BAL_LOG_CREATE'
EXPORTING
i_s_log = ls_header
IMPORTING
e_log_handle = DATA(lv_log_handle).
" 添加日志消息
LOOP AT lt_output ASSIGNING FIELD-SYMBOL(<message>).
CALL FUNCTION 'BAL_LOG_MSG_ADD_FREE_TEXT'
EXPORTING
i_log_handle = lv_log_handle
i_msgty = iv_msgty
i_text = <message>.
ENDLOOP.
" 保存日志
CALL FUNCTION 'BAL_DB_SAVE'
EXPORTING
i_t_log_handle = VALUE bal_t_logh( ( lv_log_handle ) ).
CATCH cx_root INTO DATA(lx_error).
" 错误处理
ENDTRY.
ENDMETHOD.
9. 实际项目中的应用建议
9.1 关键业务流程的日志设计
对于关键业务流程,建议设计详细的日志点:
- 流程开始/结束:记录整体执行情况
- 分支决策点:记录条件判断的依据和结果
- 数据转换点:记录重要数据的转换过程
- 外部调用点:记录接口调用参数和返回结果
示例设计:
abap复制METHOD process_order.
" 1. 流程开始记录
CL_DEMO_OUTPUT=>BEGIN_SECTION( '订单处理流程开始' ).
CL_DEMO_OUTPUT=>WRITE_DATA( |订单号: { is_order-order_id }| ).
CL_DEMO_OUTPUT=>WRITE_DATA( |客户: { is_order-customer_id }| ).
" 2. 检查库存
DATA(lv_stock) = check_stock( is_order-item_id ).
log_expression(
iv_expression = |库存检查(产品:{ is_order-item_id })|
iv_result = lv_stock ).
IF lv_stock < is_order-quantity.
" 3. 库存不足分支
CL_DEMO_OUTPUT=>WRITE_DATA( '库存不足,触发补货流程' ).
trigger_replenishment( is_order ).
RETURN.
ENDIF.
" 4. 计算价格
DATA(lv_price) = calculate_price( is_order ).
log_expression(
iv_expression = |价格计算(数量:{ is_order-quantity },单价:{ is_order-unit_price })|
iv_result = lv_price ).
" 5. 创建交货单
DATA(lv_delivery) = create_delivery( is_order ).
CL_DEMO_OUTPUT=>WRITE_DATA( |交货单创建成功: { lv_delivery }| ).
" 流程结束
CL_DEMO_OUTPUT=>WRITE_DATA( '订单处理完成' ).
CL_DEMO_OUTPUT=>DISPLAY( ).
ENDMETHOD.
9.2 性能敏感场景的优化建议
在性能敏感的场景中,可以采用以下优化策略:
- 延迟日志构建:只在需要记录时才构建日志内容
- 缓冲区设计:先将日志写入内存缓冲区,再批量输出
- 条件编译:使用预处理指令控制日志代码是否编译
优化实现示例:
abap复制METHOD fast_processing.
" 定义日志缓冲区
DATA: lt_log_buffer TYPE string_table.
" 处理逻辑
DO 1000 TIMES.
DATA(lv_result) = perform_complex_calculation( sy-index ).
" 只在调试模式下记录日志
IF gv_debug_mode = abap_true.
APPEND |迭代 { sy-index }: 结果 = { lv_result }| TO lt_log_buffer.
ENDIF.
ENDDO.
" 批量输出日志
IF gv_debug_mode = abap_true.
CL_DEMO_OUTPUT=>BEGIN_SECTION( '处理结果摘要' ).
LOOP AT lt_log_buffer INTO DATA(lv_log).
CL_DEMO_OUTPUT=>WRITE_DATA( lv_log ).
ENDLOOP.
CL_DEMO_OUTPUT=>DISPLAY( ).
ENDIF.
ENDMETHOD.
9.3 长期维护的日志策略
对于需要长期维护的项目,建议:
- 日志分类:按功能模块、事务类型等分类日志
- 版本控制:日志格式随应用版本升级而演进
- 清理机制:实现自动日志清理以避免积累
- 文档配套:编写日志使用指南供团队参考
维护友好的日志示例:
abap复制METHOD maintainable_logging.
" 使用版本标识
CL_DEMO_OUTPUT=>WRITE_DATA( '## 日志格式版本 1.2 ##' ).
" 模块标识
CL_DEMO_OUTPUT=>WRITE_DATA( '[AR-INV] 发票处理模块' ).
" 结构化上下文信息
CL_DEMO_OUTPUT=>BEGIN_SECTION( '执行上下文' ).
CL_DEMO_OUTPUT=>WRITE_DATA( |系统ID: { sy-sysid }| ).
CL_DEMO_OUTPUT=>WRITE_DATA( |客户端: { sy-mandt }| ).
CL_DEMO_OUTPUT=>WRITE_DATA( |用户: { sy-uname }| ).
CL_DEMO_OUTPUT=>WRITE_DATA( |事务码: { sy-tcode }| ).
CL_DEMO_OUTPUT=>END_SECTION( ).
" 业务日志内容...
" 结束标记
CL_DEMO_OUTPUT=>WRITE_DATA( '## 日志结束 ##' ).
CL_DEMO_OUTPUT=>DISPLAY( ).
ENDMETHOD.
10. 未来可能的增强方向
虽然CL_DEMO_OUTPUT已经提供了强大的日志记录功能,但在实际项目中还可以考虑以下增强方向:
- 日志级别过滤:实现运行时动态调整日志级别
- 远程日志收集:支持将日志发送到远程服务器
- 敏感数据脱敏:自动识别和隐藏敏感信息
- 性能监控集成:将日志与性能数据关联分析
- 可视化分析工具:开发专门的日志分析界面
一个简单的增强实现示例:
abap复制CLASS lcl_enhanced_logger DEFINITION.
PUBLIC SECTION.
METHODS:
constructor IMPORTING io_output TYPE REF TO if_demo_output OPTIONAL,
log_expression IMPORTING iv_expression TYPE string
iv_result TYPE any
iv_level TYPE i DEFAULT 1.
PRIVATE SECTION.
DATA mo_output TYPE REF TO if_demo_output.
DATA mv_log_level TYPE i.
ENDCLASS.
METHOD constructor.
mo_output = COND #( WHEN io_output IS BOUND THEN io_output ELSE cl_demo_output=>new( ) ).
mv_log_level = 1. " 默认级别
ENDMETHOD.
METHOD log_expression.
CHECK iv_level >= mv_log_level. " 级别过滤
TRY.
mo_output->write_data( |{ iv_expression } = { iv_result }| ).
" 简单脱敏处理
IF iv_expression CS 'password' OR iv_expression CS 'creditcard'.
mo_output->write_data( '警告: 可能包含敏感数据' ).
ENDIF.
CATCH cx_root.
" 错误处理
ENDTRY.
ENDMETHOD.
