免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12345下一页
最近访问板块 发新帖
查看: 243647 | 回复: 44
打印 上一主题 下一主题

一个程序员在AS400银行核心系统开发中的技术总结 [复制链接]

论坛徽章:
5
2015亚冠之阿尔艾因
日期:2015-08-10 02:23:34操作系统版块每日发帖之星
日期:2015-08-13 06:20:002015七夕节徽章
日期:2015-08-21 11:06:1715-16赛季CBA联赛之山西
日期:2016-04-13 02:36:59操作系统版块每日发帖之星
日期:2016-04-14 06:20:00
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2015-05-29 23:22 |只看该作者 |倒序浏览
本帖最后由 pacman2000 于 2015-06-07 17:43 编辑

    随着国家的自主安全可控号召,AS400系统看来在银行IT逐渐退出了。因此很遗憾,重新规划开发的AS400新核心系统就告一段落。不过,在开发过程中,有不少技术值得总结共享,如果有谬误,或有更优方法,也请大家指正。
    开发中使用的技术,基本上都是参照IBM信息中心的官方文档,链接在这里:www-01.ibm.com/support/knowledgecenter/ssw_ibm_i/welcome?lang=zh


    *操作系统版本
    系统选择了V6R1的版本,ILE环境(从OPM转到ILE不需要解释了吧)。这是因为V6R1有一个重大提升:RPG程序内部结构的大小限制从64K提升到了16M。这让DS,数组更具实用性。例如,交易程序的PARM,通常是输入接口复合DS,输出接口复合DS,遇到数组时64K就不够用。V7R1,V7R2也有不少改变,特别是V7R2,完善了自由格式,可以让H,F,D等全部拥有了自由格式写法,并且不需要/FREE,/END-FREE标识符即可自由格式固定格式混用,真是不错的选择。当时详细分析了6.1,7.1,7.2的语法改进,下面介绍下不同版本在开发上的重要改进。

    7.2
    CL语言
    对字符串新增了6个函数,%CHECK,%CHECKR,%SCAN,%TRIM,%TRIML,%TRIMR。
    新增6个转换函数,%CHAR,%DEC,%INT,%UINT,%LOWER,%UPPER。
    新增2个大小函数,%LEN,%SIZE。
    是不是CL中处理方便多了?可惜在7.2才能用,6.1只能看看了。

    C/C++语言
    没有什么需要关注的改动。

    RPG语言
    放松对IO输入输出结构的要求。使用*ALL可以让LIKEREC结构可以用在读写等任何IO操作上。这点非常有用,以后介绍LIKEREC时候再详细比较。
    增加了CTL-OPT写法,用于自由格式H表定义。
    增加了DCL-F写法,用于自由格式F表定义。
    增加了DCL-C, DCL-DS, DCL-PI, DCL-PR, DCL-S写法,用于自由格式D表定义。
    增加了DCL-PROC写法,用于子过程定义。
    不再要求/FREE,/END-FREE,自由格式和固定格式可以任意混合编写。
    %SUBDT增加参数,使得可以指定返回几位数字,例如%SUBDT(MyDate:*YEARS:4)。
    timestamp类型可以保存秒以下12位小数(纳秒?),相应的%TIMESTAMP也增加了参数用于指定小数位数。
   

    7.1
    CL语言
    可以使用RTVCLSRC从目标对象来获取ILE CL的源代码了。不过要求编译时ALWRTVSRC参数指定为*YES。
    INT,UINT类型长度可以扩展到8字节。
    可以在编译程序时,用DBGENCKEY,使得只有输入正确的KEY,才能看到源码视图。(这个,嘿嘿)
    CL中的INCLUDE支持嵌套了。

    C/C++语言
    没有什么需要关注的改动。

    RPG语言
    SORTA和%LOOKUP可以依据DS结构的某一个字段,来排序或检索数组啦。例如:SORTA custDs(*).amount_owing; elem = %LOOKUP("K" : custDs(*).account_status);
    SORTA可以用(A),(D)来正序,逆序排序数组。
    增加了%SCANRPL函数,用于将一个字符串中的子串,替换为指定的字符串。(报错信息替换的神器啊,可惜V6R1不能用)
    可以在编译程序时,用DBGENCKEY,使得只有输入正确的KEY,才能看到源码视图。


    6.1
    CL语言
    增加CLOSE语句,可以关闭RCVF打开的文件,用于多次读取一个文件的场景。
    增加INCLUDE语句,包含另外CL一个源文件。

    C/C++语言
    没有什么需要关注的改动。

    RPG语言
    文件定义时候可以指定QUALIFIED,记录格式名变成MYFILE.MYFMT,避免文件内字段名字对程序全局字段的名字污染。但文件操作必须使用DS结构。这点稍后会详细介绍。
    EXTDESC和EXTFILE(*EXTDESC),使得可以编译期不再需要绑定文件描述,而使用字符串形式的'LIBNAME/FILENAME',运行期再去打开文件。
    EXTNAME可以使用字符串形式'LIBNAME/FILENAME',同样不需要编译器绑定文件。
    扩大DS,可变字符串等的最大限制,大小扩到16M。可变字符串的VARYING关键字允许指定2或4字节存放长度,%ADDR(varying : *DATA)可以获取到除去长度后的数据位置指针。
    DIM和OCCURS数组的最大限制,元素个数扩充到16M个,但总大小不超过16M。
    字符串常量大小扩到16k。
    TEMPLATE关键字可用于文件定义和结构定义,不占用存储空间,通常为了LIKEFILE,LIKE,LIKEDS使用。TEMPLATE DS可以有INZ定义,方便参照它的结构使用INZ(*LIKEDS)来初始化。

论坛徽章:
5
2015亚冠之阿尔艾因
日期:2015-08-10 02:23:34操作系统版块每日发帖之星
日期:2015-08-13 06:20:002015七夕节徽章
日期:2015-08-21 11:06:1715-16赛季CBA联赛之山西
日期:2016-04-13 02:36:59操作系统版块每日发帖之星
日期:2016-04-14 06:20:00
2 [报告]
发表于 2015-05-29 23:41 |只看该作者
本帖最后由 pacman2000 于 2015-05-30 11:08 编辑

    *COPYRIGHT设置
    让我们从一个比较无聊的技术开始吧,哈哈。COPYRIGHT就是编译成目标后,可以用DSPPGM,DSPMOD等,翻到版权页,显示的字符串。这个要怎么弄呢?考虑到系统有很多程序,因此采用了设置包含源文件的方式实现。


    RPGLE
    应用程序:
  1. H/COPY DSCPPGM,HEAD
复制代码
.
    HEAD源文件:
  1. HCOPYRIGHT('Firebird V2.1 corebanking system')
  2. HDATFMT(*ISO) TIMFMT(*ISO) DATEDIT(*YMD)
复制代码
.

    C/C++
    应用程序:
  1. #include "dscppgm/cpyrgt_h"
复制代码
.
    CPYRGT_H源文件:
  1. #ifndef CPYRGT_H
  2. #define CPYRGT_H
  3. #pragma comment(copyright,"Firebird V2.1 corebanking system")
  4. #endif
复制代码
.


    CLLE
    应用程序:
  1.     INCLUDE    SRCMBR(CLHD) SRCFILE(DSCPPGM)
复制代码
.

    CLHD源文件:
  1.     COPYRIGHT  TEXT('Firebird V2.1 corebanking system')
复制代码
.


    但是,AS400的CL在COPYRIGHT处理上并不完美。RPG,C都可以设置DBCS中文字符串,CL带中文的话编译报错。DEBUG时,CL也会因为INCLUDE引入而导致没有普通视图。这一点,不知道高版本是否有改善,有环境的话可以测试验证一下。

论坛徽章:
5
2015亚冠之阿尔艾因
日期:2015-08-10 02:23:34操作系统版块每日发帖之星
日期:2015-08-13 06:20:002015七夕节徽章
日期:2015-08-21 11:06:1715-16赛季CBA联赛之山西
日期:2016-04-13 02:36:59操作系统版块每日发帖之星
日期:2016-04-14 06:20:00
3 [报告]
发表于 2015-05-30 10:59 |只看该作者
本帖最后由 pacman2000 于 2015-05-31 15:41 编辑

*数据区域DATA AREA的使用

数据区域DTAARA,是一小片存储对象,通常使用1-2k大小的CHAR类型。持久化的命名数据区域,可以在不同job间交互数据。在系统中使用了这种方式存放配置参数,方便做到不重启应用的动态刷新。另外还有几个特殊数据区域,常见的是*LDA,1k大小的job自有共享区域,可用于job内不同程序间的数据交互,起到全局空间的作用。*LDA不能持久化,随着job结束而消失,因此可以认为是一片job特有的内存,不需加锁访问,速度更快。

在程序中使用DTAARA比较简单,参照下面的例子。

C/C++
  1. #include <xxdtaa.h>  //读写数据区域使用的头文件
  2. ...
  3. _DTAA_NAME_T dtaa = {"MNAR      ", "*LIBL     "};  //定义命名数据区域的名称,如果是LDA,则为{"*LDA      ", "          "}
  4. QXXCHGDA(dtaa, DBG_START, sizeof(data), data);  //从DBG_START位开始,写入字符串data内容到数据区域
  5. QXXRTVDA(dtaa, 1, sizeof(dtaa_st), (char*)dtaa_s);  //从第一位开始获取数据区域内容,存放到自定义的dtaa_st结构变量dtaa_s中
复制代码
.

RPGLE
*LDA的例子
  1.      D*定义公共数据,使用*LDA,内容为TRAR,INHD,OTHD结构的组合
  2.      DT_TRAR         E DS                  EXTNAME(TRAR) QUALIFIED TEMPLATE
  3.      DT_INHD         E DS                  EXTNAME(INHD) QUALIFIED TEMPLATE
  4.      DT_OTHD         E DS                  EXTNAME(OTHD) QUALIFIED TEMPLATE
  5.      DS_LDA           UDS                  DTAARA(*LDA)  QUALIFIED
  6.      D TRAR                                LIKEDS(T_TRAR)
  7.      D INHD                                LIKEDS(T_INHD)
  8.      D OTHD                                LIKEDS(T_OTHD)
  9.      ...
  10.      C*读取LDA,并进行错误处理。LDA无需上锁。
  11.      C                   IN(E)     S_LDA
  12.      C                   IF        (%ERROR)
  13.      C*读取失败
  14.      C                   ENDIF
  15.      ...
  16.      C*写入LDA,并进行错误处理。LDA无需上锁。
  17.      C                   OUT(E)    S_LDA
  18.      C                   IF        %ERROR
  19.      C*写入失败
  20.      C                   ENDIF
复制代码
.

命名DTAARA的例子
  1.      D*总长度256字节的数据区域BTAR,内容为5P0的变量MAXJOBS
  2.      DS_BTAR          UDS           256    DTAARA('BTAR') QUALIFIED
  3.      D MAXJOBS                        5P 0
  4.      ...
  5.      C*从BTAR获取MAXJOBS值
  6.      C     *LOCK         IN        S_BTAR
  7.      C                   UNLOCK    S_BTAR
复制代码
.

在IN读取命名数据区域时,可以用*LOCK选择是否加锁。加锁以后,访问数据区域的其他程序就只能读不能写。如果执行到不加*LOCK的OUT,那么写完即释放锁。如果OUT加了*LOCK,那么锁将会继续保持。使用UNLOCK可以直接在不写入的情况下解除锁。


CLLE及命令行
系统提供了几个命令来操作数据区域。
CRTDTAARA,创建命名数据区域(*LDA不需创建),创建时也可指定初始值,如CRTDTAARA DTAARA(CUSTOMER) TYPE(*CHAR) LEN(100) VALUE('INIT') TEXT(’Customer name area’)
DSPDTAARA,显示或打印数据区域的内容,如DSPDTAARA  DTAARA(MYLIB/MYDTA)
RTVDTAARA,获取数据区域内容到CL变量,可以指定从第几位取多少位,如RTVDTAARA  DTAARA(*LDA (5,2)) RTNVAR(&VAL)
CHGDTAARA,与获取类似,写入数据区域,如果字符串长度不足补空格,如CHGDTAARA  DTAARA(*LDA (5,4)) VALUE('OK'),实际5-8位写入'OK  '
DLTDTAARA,删除一个命名数据区域,如DLTDTAARA  DTAARA(MYLIB/MYDTA)

论坛徽章:
5
2015亚冠之阿尔艾因
日期:2015-08-10 02:23:34操作系统版块每日发帖之星
日期:2015-08-13 06:20:002015七夕节徽章
日期:2015-08-21 11:06:1715-16赛季CBA联赛之山西
日期:2016-04-13 02:36:59操作系统版块每日发帖之星
日期:2016-04-14 06:20:00
4 [报告]
发表于 2015-06-07 22:40 |只看该作者
本帖最后由 pacman2000 于 2015-06-07 22:43 编辑

*用户空间USER SPACE的使用

用户空间USER SPACE,是AS400所提供进程间通讯的另一个机制,可以保存一块较大的持久化数据。常用的三大机制,DATA AREA在核心系统中用于控制参数的设置,例如批处理平台并发数控制,联机平台各种标志,以及全局内容在*LDA的跨PGM保存传递。DATA QUEUE可用于进程间传递消息数据,因核心系统设计上处理进程的隔离性而没有用到。USER SPACE则用于实现输出报文的灵活性,保存核心系统交易处理过程中,可能产生返回的凭证打印报文接口段。
USER SPACE最大长度可达16M,必须命名以持久化。由于在系统中用于暂存一笔联机交易需要返回的附加报文数据,因此对持久化其实没有要求,但性能要求很高,又不能互相影响。于是将USER SPACE建立在QTEMP中。这样不同JOB各自有一份使用,而且QTEMP数据系统应该是在内存中建立的,恰好符合要求。

那么程序中如何访问呢,可以看实际使用的例子。

创建USER SPACE,名称为QTEMP/JOBADDUS。

  1.              PGM        PARM(&SPCLEN)
  2.              INCLUDE    SRCMBR(CLHD) SRCFILE(DSCPPGM)
  3.              DCL        VAR(&PASSPCNM) TYPE(*CHAR) LEN(20)
  4.              DCL        VAR(&SPCATTR) TYPE(*CHAR) LEN(10)
  5.              DCL        VAR(&SPCLEN) TYPE(*UINT) LEN(4)
  6.              DCL        VAR(&SPCVALUE) TYPE(*CHAR) LEN(1)
  7.              DCL        VAR(&SPCAUTH) TYPE(*CHAR) LEN(10)
  8.              DCL        VAR(&SPCTEXT) TYPE(*CHAR) LEN(50)
  9.              CHGVAR     VAR(&PASSPCNM) VALUE('JOBADDUS  QTEMP     ')
  10.              CHGVAR     VAR(&SPCAUTH) VALUE('*CHANGE')
  11.              CHGVAR     VAR(&SPCTEXT) VALUE('附加报文用户空间')
  12.              CHGVAR     VAR(&SPCVALUE) VALUE(X'00')
  13.              CALL       PGM(QUSCRTUS) PARM(&PASSPCNM &SPCATTR +
  14.                           &SPCLEN &SPCVALUE &SPCAUTH &SPCTEXT)
  15.              MONMSG     MSGID(CPF9870)
  16.              ENDPGM
复制代码
.

因为JOB结束时QTEMP自动释放,而JOB不结束的话USER SPACE可以重复使用,因此不需要人为去删除这个USER SPACE。

使用这个USER SPACE,会有两种情况。
一是交易运行过程中,产生需要附加的打印接口数据,这时候调用下面的程序记录进USER SPACE,注意,同时将已附加长度写进*LDA记录。另一种情况是组返回报文时,读取数据打包进报文,这个用的是后续的USER SPACE指针操作。

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <arpa/inet.h>

  4. #include "dscppgm/cpyrgt_h"
  5. #include "config_h"
  6. #include "msginfo_h"
  7. #include "opdtaac_h"

  8. extern void JOBUSPTR(char **usptr);
  9. extern void fill_str(char *buf, const char *str, int len);
  10. extern int get_output_arrays_count(oa_otct*);
  11. extern int set_otlen(int len);

  12. /* parm1 MESG
  13.    parm2 ITNAME  10A
  14.    parm3 ITCNT   2B  hostorder
  15.    parm4 ITPLEN  2B  hostorder
  16.    parm5 ITBUF   ITCNT*ITPLEN
  17. */
  18. int main(int argc, char **argv)
  19. {
  20.   oa_otct oa;
  21.   rpg_msg_info *rpginfo;
  22.   int olen, tlen;
  23.   unsigned short pcnt, plen, tmp;
  24.   char *obuf, *itbuf;
  25.   char *itnm;
  26.   char linebuf[LINENO_LEN+1];

  27.   if (argc<2)
  28.     return -1;
  29.   rpginfo=(rpg_msg_info *)argv[1];
  30.   if (argc!=6)
  31.   {
  32.     fill_str(rpginfo->msgflnm, __FILE__, FILENM_LEN);
  33.     sprintf(linebuf, "%6d", __LINE__);
  34.     fill_str(rpginfo->msgline, linebuf, LINENO_LEN);
  35.     fill_str(rpginfo->msgid, "EPLMNOPCK ", MSG_ID_LEN);
  36.     fill_str(rpginfo->msgtext, "组附加报文接口不正确", MSG_TEXT_LEN);
  37.     fill_str(rpginfo->msgotds, "", MSG_TEXT_LEN);
  38.     return -1;
  39.   }
  40.   itnm=argv[2];
  41.   pcnt=*(unsigned short *)argv[3];
  42.   plen=*(unsigned short *)argv[4];
  43.   itbuf=argv[5];

  44.   JOBUSPTR(&obuf);
  45.   get_output_arrays_count(&oa);
  46.   olen=oa.ot_len;
  47.   obuf += olen;

  48.   tlen = olen + ITNAME_SIZE + ITCNT_SIZE + ITPLEN_SIZE
  49.          + (pcnt==0 ? plen : pcnt*plen);
  50.   if (tlen > DAT_MAX_LEN)
  51.   {
  52.     char errbuf[MSG_TEXT_LEN];

  53.     fill_str(rpginfo->msgflnm, __FILE__, FILENM_LEN);
  54.     sprintf(linebuf, "%6d", __LINE__);
  55.     fill_str(rpginfo->msgline, linebuf, LINENO_LEN);
  56.     fill_str(rpginfo->msgid, "EPLMNOLEN ", MSG_ID_LEN);
  57.     sprintf(errbuf, "组附加报文时长度%d + %d超过最大长度%d",
  58.             olen, tlen-olen, DAT_MAX_LEN);
  59.     fill_str(rpginfo->msgtext, errbuf, MSG_TEXT_LEN);
  60.     fill_str(rpginfo->msgotds, "", MSG_TEXT_LEN);
  61.     return -1;
  62.   }

  63.   fill_str(obuf, itnm, ITNAME_SIZE);
  64.   obuf += ITNAME_SIZE;
  65.   tmp = htons(pcnt);
  66.   memcpy(obuf, &tmp, ITCNT_SIZE);
  67.   obuf += ITCNT_SIZE;
  68.   tmp = htons(plen);
  69.   memcpy(obuf, &tmp, ITPLEN_SIZE);
  70.   obuf += ITPLEN_SIZE;
  71.   memcpy(obuf, itbuf, pcnt==0 ? plen : pcnt*plen);

  72.   set_otlen(olen);
  73.   return tlen;
  74. }
复制代码
.
这个程序将一个报文接口,以ITNAME接口名,ITCNT接口数组条数,ITLEN接口单条长度,ITBUF接口数据的方式,打包记录进USER SPACE。其中,JOBUSPTR用于获取USER SPACE的指针,然后就像普通内存一样操作。下面就是JOBUSPTR的程序。

  1.              PGM        PARM(&USPTR)
  2.              INCLUDE    SRCMBR(CLHD) SRCFILE(DSCPPGM)
  3.              DCL        VAR(&PASSPCNM) TYPE(*CHAR) LEN(20)
  4.              DCL        VAR(&USPTR) TYPE(*PTR)
  5.              CHGVAR     VAR(&PASSPCNM) VALUE('JOBADDUS  QTEMP     ')
  6.              CALL       PGM(QUSPTRUS) PARM(&PASSPCNM &USPTR)
  7.              ENDPGM
复制代码
.

核心系统中的用法到此为止。实际上,USER SPACE相关的命令和调用有不少,修改内容的方式除了获取指针,还可以用QUSRTVUS获取USER SPACE内容,QUSCHGUS修改USER SPACE内容。这两个调用以字符串的形式操作。遗憾的是,CL对USER SPACE的支持较少,需要用到的话自己写程序扩充吧。

论坛徽章:
0
5 [报告]
发表于 2015-06-09 11:05 |只看该作者
给大师点个赞,辛苦了!很受用

论坛徽章:
5
2015亚冠之阿尔艾因
日期:2015-08-10 02:23:34操作系统版块每日发帖之星
日期:2015-08-13 06:20:002015七夕节徽章
日期:2015-08-21 11:06:1715-16赛季CBA联赛之山西
日期:2016-04-13 02:36:59操作系统版块每日发帖之星
日期:2016-04-14 06:20:00
6 [报告]
发表于 2015-06-09 17:23 |只看该作者
cuilei286 发表于 2015-06-09 11:05
给大师点个赞,辛苦了!很受用



哈哈,因为接下来可能不太会用400了,所以总结一下,一方面共享知识,另外也免得以后自己忘记了。
还有不少技术上的功能点,以后会慢慢补充。

论坛徽章:
49
15-16赛季CBA联赛之福建
日期:2016-06-22 16:22:002015年亚洲杯之中国
日期:2015-01-23 16:25:12丑牛
日期:2015-01-20 09:39:23未羊
日期:2015-01-14 23:55:57巳蛇
日期:2015-01-06 18:21:36双鱼座
日期:2015-01-02 22:04:33午马
日期:2014-11-25 09:58:35辰龙
日期:2014-11-18 10:40:07寅虎
日期:2014-11-13 22:47:15申猴
日期:2014-10-22 15:29:50摩羯座
日期:2014-08-27 10:49:43辰龙
日期:2014-08-21 10:47:58
7 [报告]
发表于 2015-06-12 23:25 |只看该作者
pacman2000 发表于 2015-06-09 17:23
哈哈,因为接下来可能不太会用400了,所以总结一下,一方面共享知识,另外也免得以后自己忘记了。
还 ...


感谢楼主分享哈~

论坛徽章:
0
8 [报告]
发表于 2015-06-13 11:22 |只看该作者
感谢楼主分享~

论坛徽章:
12
数据库技术版块每日发帖之星
日期:2015-07-08 22:20:00IT运维版块每日发帖之星
日期:2016-05-01 06:20:00IT运维版块每周发帖之星
日期:2016-03-07 16:27:44IT运维版块每月发帖之星
日期:2016-03-07 16:25:25IT运维版块每日发帖之星
日期:2016-02-21 06:20:00IT运维版块每日发帖之星
日期:2016-02-20 06:20:00数据库技术版块每日发帖之星
日期:2016-02-06 06:20:00IT运维版块每日发帖之星
日期:2016-01-30 06:20:00IT运维版块每日发帖之星
日期:2016-01-03 06:20:00IT运维版块每日发帖之星
日期:2015-11-29 06:20:00IT运维版块每日发帖之星
日期:2015-08-10 06:20:00数据库技术版块每日发帖之星
日期:2016-06-16 06:20:00
9 [报告]
发表于 2015-06-15 14:14 |只看该作者
18摸现在也仅仅是维持as400了吧?

论坛徽章:
5
2015亚冠之阿尔艾因
日期:2015-08-10 02:23:34操作系统版块每日发帖之星
日期:2015-08-13 06:20:002015七夕节徽章
日期:2015-08-21 11:06:1715-16赛季CBA联赛之山西
日期:2016-04-13 02:36:59操作系统版块每日发帖之星
日期:2016-04-14 06:20:00
10 [报告]
发表于 2015-06-18 07:18 |只看该作者
本帖最后由 pacman2000 于 2015-06-18 07:19 编辑

*多语言与多环境

系统对多语言的支持,这在某些情况下,也是非常有用的,例如将核心系统部署为海外分行系统。通常情况下,海外系统独立搭建,操作人员部分是当地人员,也可能有派驻人员。同一套环境的多语言随时切换,其实并不存在实际场景,因为数据表内容存放,只会按照一个语言标准。举个例子,核心系统的户名地址等字段,是根据系统所在国家设语言,存放成不同文字,比如中文,而这些字段都会在输入输出中展示。因此,即使是将用户环境和操作界面切换成英文环境,字段内容仍会出现中文。另外,多语言不应额外增加处理的负担。
于是,系统的多语言,就分为两个方面。一是这套系统是否可以轻松做到转向其他语言的翻译,即如何作为一套海外系统部署。二是当系统后台维护人员运行工具时,如果能根据用户做到参数说明和输出展示的语言选择,尽可能符合本地人员和派驻人员的习惯。下面以中文(默认)和英文(辅助)为例,总结一下做法。

数据表部分,对于不同国家的版本,将各数据存放对象的CCSID设置为相应国家语言代码,如中文则为1388。
应用程序部分,区别在于返回报文的某些字符串字段内容语言不同。这些字段的数据来源,除了数据库中直接记录的字段,还可以在应用程序中拼接而成,比如出错信息。核心系统使用了错误信息表,在RPG程序中做错误信息的拼接组装。例如,“EIOER”错误代码内容为“接口&1字段&2值&3不正确”。其中&1,&2,&3由应用程序字符串代入。因此,应用程序中,全部将文本定义成命名为C_MGXXXX的常量。制作其他语言版本时,只需翻译所有C_MG常量,错误信息表和文件的中文描述即可(因为某些错误信息,会拼接表的中文信息,例如:更新表&1失败,&1为PF的中文描述活期分户账,如何获取在统一错误处理部分详细介绍)。
工具部分,就需要考虑操作用户不同时的语言不同了。AS400为CMD提供了多语言提示文件的方法,但CMD只是发起命令界面,执行程序的过程显示就没有办法了。因此换了一种做法,将工具的CMD,PGM等分多套语言版本编译到不同的目标库中。如XXXOBJMON放置默认的中文工具程序,XXXOBJMONE放置辅助的英文版本程序。然后通过用户USRPRF的初始化程序不同,来指定LIBL中的先后顺序,达到执行的不同语言版本的效果。

下面是中文语言习惯的用户USRPRF初始化程序。

  1.              PGM
  2.              INCLUDE    SRCMBR(CLHD) SRCFILE(DSCPPGM)
  3.              DCL        VAR(&PFX) TYPE(*CHAR) LEN(3)
  4.              DCL        VAR(&JRN) TYPE(*CHAR) LEN(10)
  5.              DCL        VAR(&JRNLIB) TYPE(*CHAR) LEN(10)
  6.              DCL        VAR(&OTHLIB) TYPE(*CHAR) LEN(10)
  7.              CALL       PGM(GETPREFIX) PARM(&PFX)
  8.              CHGVAR     VAR(&JRN) VALUE(&PFX *CAT 'JRN')
  9.              CHGVAR     VAR(&JRNLIB) VALUE(&PFX *CAT 'SYSJRN')
  10.              CHGVAR     VAR(&OTHLIB) VALUE(&PFX *CAT 'OBJOTH')
  11.              CHGSYSLIBL LIB(QSYS2989)
  12.              CHGCURLIB  CURLIB(&OTHLIB)
  13.              STRCMTCTL  LCKLVL(*CHG) CMTSCOPE(*JOB) +
  14.                           DFTJRN(&JRNLIB/&JRN)
  15.              MONMSG     MSGID(CPF8351)
  16.              ENDPGM
复制代码
.

下面是英文语言习惯的用户USRPRF初始化程序。注意在OBJMON前会先搜索OBJMONE。

  1.              PGM
  2.              INCLUDE    SRCMBR(CLHD) SRCFILE(DSCPPGM)
  3.              DCL        VAR(&PFX) TYPE(*CHAR) LEN(3)
  4.              DCL        VAR(&JRN) TYPE(*CHAR) LEN(10)
  5.              DCL        VAR(&JRNLIB) TYPE(*CHAR) LEN(10)
  6.              DCL        VAR(&MONLIB) TYPE(*CHAR) LEN(10)
  7.              DCL        VAR(&ENULIB) TYPE(*CHAR) LEN(10)
  8.              DCL        VAR(&OTHLIB) TYPE(*CHAR) LEN(10)
  9.              CALL       PGM(GETPREFIX) PARM(&PFX)
  10.              CHGVAR     VAR(&JRN) VALUE(&PFX *CAT 'JRN')
  11.              CHGVAR     VAR(&JRNLIB) VALUE(&PFX *CAT 'SYSJRN')
  12.              CHGVAR     VAR(&MONLIB) VALUE(&PFX *CAT 'OBJMON')
  13.              CHGVAR     VAR(&ENULIB) VALUE(&PFX *CAT 'OBJMONE')
  14.              CHGVAR     VAR(&OTHLIB) VALUE(&PFX *CAT 'OBJOTH')
  15.              ADDLIBLE   LIB(&ENULIB) POSITION(*BEFORE &MONLIB)
  16.              CHGCURLIB  CURLIB(&OTHLIB)
  17.              STRCMTCTL  LCKLVL(*CHG) CMTSCOPE(*JOB) +
  18.                           DFTJRN(&JRNLIB/&JRN)
  19.              MONMSG     MSGID(CPF8351)
  20.              ENDPGM
复制代码
.

其中,GETPREFIX程序,是获取当前应用环境。系统在一台机器上可以部署多套环境,以前三位环境代码区分。所有的库名前三位即为环境代码,用户登录时,就可以根据LIBL的设置,对应到相应环境。应用程序编写时,尽量使用*LIBL查找目标,如果确需指定库名,则先调用GETPREFIX,根据用户USRPRF的初始化程序所在库前三位,获得环境代码。

  1.              PGM        PARM(&PREFIX)
  2.              INCLUDE    SRCMBR(CLHD) SRCFILE(DSCPPGM)
  3.              DCL        VAR(&PREFIX) TYPE(*CHAR) LEN(3)
  4.              DCL        VAR(&PGMLIB) TYPE(*CHAR) LEN(10)
  5.              RTVUSRPRF  INLPGMLIB(&PGMLIB)
  6.              CHGVAR     VAR(&PREFIX) VALUE(%SST(&PGMLIB 1 3))
  7.              ENDPGM
复制代码
.

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP