Java 企业应用
不要温柔的走入那个良夜

----------------------- Page 1---------------
                

1    文档描述
1.1    目标和范围
编制本文档的目的是为了给开发Maximo6.20应用程序提供向导。
1.2    定义和缩写
Abbr.    Definition
Maximo620    美国MRO公司(原PSDI公司)出品的企业资产管理产品,版本6.20
1.3    参考
Document Name    Document Title
开发模式.doc    
    
    
1.4    角色职责
Roles    Responsibilities
罗慧    撰写本文档
徐永远    审核修改本文档
魏明智    添加丰富开发指南。

2    命名规则
2.1    基本准则
1、    总体说来,按照Maximo的包结构,存放相应的类,将psid改为com.jxkj即可。
2、    公司开发的类,统一放在com.jxkj包中。
3、    应用程序业务逻辑类,请放在com.jxkj.app.包中。
4、    应用程序的页面操作类,请放在com.jxkj.webclient.beans.包中。
5、    工作流过程名,一般为应用程序的名字。
6、    主表与子表之间的联系名,请直接使用子表的名称。
2.2    类名的命名规则
以下的规则,按优先级,从高到低排列,如果有冲突,请按优先级高的方式命名。
1、    关于类名的命名规则,请多多熟悉Maximo本身源码类名的命名规则。
2、    扩展原有的类,请不要使用相同的名字,最好加上“Jx”关键字。
3、    直接从Mbo或StatefulMbo继承的类,最好使用表名作为类名。
4、    直接从MboSet继承的类,最好使用表名加上“Set”作为类名。
5、    远程接口的名称,最好都加上Remote。
6、    字段的类名,最好以Fld开头。

3    开发说明
3.1    搭建开发环境
3.1.1    Maximo6.2发布为开发模式
Maximo6.20采用的是ear包发布到weblogic8.1中的,为了方便开发与测试,我们需要将其发布为开发模式(非产品的EAR模式)。
1、    将maximo.ear解压到maximo文件夹。(怎么解压不用我说了吧!)
2、    再将解压后的目录中的文件businessobjects.jar解压为businessobjects.jar文件夹。注意文件夹名要与原文件名相同。
3、    同理,解压maximouiweb.war以及properties.jar
4、    完毕
 
3.1.2    配置Eclipse集成开发环境
对于Maximo6的二次开发,这里推荐使用基于eclipse的集成开发环境。
1、安装Eclipse;
2、安装MyEclipse,并注册(MyEclipse->Update Subscription);
3、安装RMI插件
?    解压net.genady.rmi_1.6.5.zip到<%eclipse%> 目录;
?    拷贝rmi.jar到<%eclipse%>\plugins\net.genady.rmi_1.6.5 directory
?    在命令行下运行“java Keygen”生成license;
?    在菜单中选Window\Preferences\Java\RMI,填入License;
?    使用RMI进行编译
 
 

4、    集成应用服务器
?    点击窗口-〉首选项配置与 Myecplise相关的信息
 
?    在 myeclipse中配置 Application Servers 相关信息
 
说明: 
?    weblogic8 配置 
选择 Enable 
bea根目录:安装bea的目录如(c:\bea) 
weblogic81的根目录  如(C:\bea\weblogic81) 
domain的用户名:登陆控制台的用户名 
domain的密码:登陆控制台的密码 
domain的路径  :如C:\bea\user_projects\domains\SCMIS 
domain的名称:发布的domain的名称 

    file:///C|/Documents and Settings/Administrator/桌面/maximo60开发指南.txt(第 1/24 页)[2010-9-28 9:01:18]

----------------------- Page 2-----------------------

     file:///C|/Documents and Settings/Administrator/桌面/maximo60开发指南.txt

服务的名称:如myserver 
IP地址和端口号:localhost:7001 
安全文件:C:\bea\weblogic81\server\lib\weblogic.policy 
这样,你就可以在eclipse中启动和停止服务了。 
?    JDK配置:建议使用BEA带的JRE,以提高执行效率 
点击ADD  增加bea提供的JRE,同时为该JRE指定参数:
 
指定的参数为: 
-ms256m  
-mx512m 
-Djava.library.path="C:/bea/weblogic81/server/bin"  
-Dweblogic.management.discover=false  
-Dweblogic.ProductionModeEnabled=false 
?    在 path中增加 classpath
在Weblogic 8下面配置Paths,加入BEA安装路径下/weblogic81/server/lib中的webservices.jar和 weblogic.jar 两个包。如果需要其他的包,也在这里加入,建议加入 oracle 对应的驱动程序包。
 
这样就可以在 eclipse 中进行单步调试了,只要你在 eclipse里启动服务后,设置断点,当程序运行到断点时,就会进入 eclipse 的调试模式,同时针对表现层的程序支持热发布。针对MBO等程序可以进行单步跟踪。
?    其他的配置根据大家自己的喜好进行配置。 
?    在窗口-〉首选项->已安装的 JRE 中调整 JRE 的缺省参数
 

5、    创建工程
创建一个“Java Project”,加入一些必须lib,参考下图所示。其中maximouiweb .jar是手动将maximo\maximouiweb.war\WEB-INF\classes下的文件打包而成,其余都可以拷贝现成的。
 
6、    使用ant部署开发环境
怎么安装ant就不用我说了吧!只提供一个build.xml文件作为模板
<?xml version="1.0"?>
<project name="Maximo620 Copy Files" basedir=".">
    
    <property name="BOpath" location="D:/maximo620/Maximo/deployment/develop/maximo/businessobjects.jar/com/jxkj/app"/>    
    <property name="WebPath" location="D:/maximo620/Maximo/deployment/develop/maximo/maximouiweb.war/WEB-INF/classes/com/jxkj/webclient"/>
    
    <target name="copy businessobjects"  description="将编译过的class考贝到maximo的发布目录(业务类)">        
        
        <copy todir="${BOpath}"  >
            <fileset dir="classes/com/jxkj/app">
                <include name="**/**.class"/>                
            </fileset>
        </copy>        
    </target>
    
    <target name="copy webclient"  description="将编译过的class考贝到maximo的发布目录(客户端类)">                
            <copy todir="${WebPath}"  >
                <fileset dir="classes/com/jxkj/webclient">
                    <include name="**/**.class"/>                
                </fileset>
            </copy>
        </target>
</project>
    

7、    运行跟踪
 

3.1.3    配置JBuilder集成开发环境
3.1.3.1    配置weblogic
1、    打开Jbuider
2、    选择菜单Enterprise->Configure Servers
3、    配置如下信息:
 
    参数参考:
Home Directory:D:/bea8/weblogic81/server
Main Class: weblogic.Server
VM Parameters:添加 -Xms512m -Xmx924m -XX:MaxPermSize=256m ,其它保持不变。
Server Paramters:
Working directory:选择你发布的域。
4、    配置Custom如下图:
 
5、    新建工程,选择project->project properties->server配置服务如下图:
 
6、    新建一个调试环境,project->project properties->run->new->run type选择server,其它默认即可。
3.1.3.2    配置类
选择 project -> project properties->path,如下图示:
注意:JDK版本,一定要用Weblogic8自带的JDK,保证兼容。
 

3.2    第一个应用程序
3.2.1    业务描述
做一个单表的增、删、改、查业务,以下业务为黄龙滩实际程序。
3.2.1.1    应用设计
属性    描述
应用程序名    Abnormity(异动)
应用程序模块名    ASSET
应用程序位置    371
应用程序表    Abnormity(主对象)
应用程序关联表    Asset(资产):与资产表通过AssetNum字段关联,在Asset应用程序中添加显示资产异动情况的显示。资产应用中可以编辑异动情况。
    Location(位置):与位置表通过Location字段关联,在Location应用程序中添加显示位置异动情况的显示。位置应用中可以编辑异动情况。
说明    

3.2.1.2    数据表设计
3.2.1.2.1    设备异动Abnormity 
字段名    类型    列标题    说明
AbnormityId    Integer(12)    请假标识    唯一标识,系统自动生成,不要改。
CHANGEBY    UPPER(30)    更改人    = PERSON. PERSONID
CHANGEDATE    DateTime    更改时间    默认为SYSDATE
HISTORYFLAG    YORN not null    历史标志    默认为0
AbnormityNum    upper(12) not null    单号    自动增长
Description    ALN(100)    描述    有长描述
ASSETNUM    Upper(30)    资产编号    =Asset.AssetNum,资产与位置必填一个
LOCATION    Upper(30)    位置编号    =Locations.Location,资产与位置必填一个
LaunchDate    Date    投运时间    
SourceParam    ALN(100)    原设备参数    有长描述
AbnormityDate    Date    异动时间     
NewParam    ALN(100)    异动后参数    有长描述
Reason    ALN(100)    异动原因    有长描述
SITEID    UPPER(8)    地点标识符    = SITE. SITEID
ORGID    UPPER(8)    组织机构    = ORGANIZATION. ORGID
主列:AbnormityNum,SITEID

3.2.2    开发步骤
3.2.2.1    第一步建立数据表

     file:///C|/Documents and Settings/Administrator/桌面/maximo60开发指南.txt(第 2/24 页)[2010-9-28 9:01:18]

----------------------- Page 3-----------------------

    file:///C|/Documents and Settings/Administrator/桌面/maximo60开发指南.txt

1、    启动Maximo,转到配置,数据库配置。
2、    点击新建对象。
3、    输入相关信息,如下图,注意这里对象即是表名ABNOREMITY、服务输入CUSTAPP、级别选择SITE,如果不是工作流表,请不要选中主对象,存储分区,是你的分区表空间。
 
4、    添加字段信息,注意,新建表之后,系统会自动生成一些字段,并未在表设计中,写出来,默认即可。
 
5、    da
3.2.2.2    第二步建立应用程序

3.3    创建域
3.3.1    域的分类
域即是值列表,是用于对象属性值的选择列表。
Maximo6中域分ALN域、同义词域(Synonym)、数字域(Numeric)、数字范围域(Numeric Range)、表域(Table)、交叉域(Cross Over)。域的主要信息保存在MAXDOMAIN表里,字段值保存在相应的表中,其中的对应关系如下图所示:
 

例如:对于一个同义词域,可以看到在MAXDOMAIN表中有一条记录对应和在SYNONYMDOMAIN表中的若干条记录。
MAXDOMAIN Table
DOMAINID    DOMAINTYPE     MAXTYPE    LENGTH     DESCRIPTION
POSTATUS    SYNONYM        UPPER    6     PO Status

SYNONYMDOMAIN Table
DOMAINID    MAXVALUE    VALUE    DESCRIPTION
POSTATUS    APPR    APPR    Approved
POSTATUS    CAN    CAN    Canceled
POSTATUS    CLOSE    CLOSE    Closed
POSTATUS    INPRG    INPRG    In Progress
POSTATUS    WAPPR    WAPPR    Waiting on Approval

3.3.2    创建域
点击转到——配置——域,进入如下图所示域的操作页面。
 

 
注意:同义词域在页面无法添加,只能直接在数据库中添加。添加同义词域可以参见2.3.1创建工作流状态同义词域。
3.4    开发自定义应用程序
3.4.1    创建模块
模块指的是点击“转到”弹出的下拉列表中的各个应用模块。
Maximo没有提供创建模块的页面,必须在数据库中利用sql语句在MAXMODULES表中添加。
添加模块后还必须MAXMENU中添加菜单。
例如:
insert into MAXMODULES (MODULE, DESCRIPTION, MAXMODULESID)
values ('TR', '技改', maxmodulesseq.nextval);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID)
values ('MODULE', 'TR', 4000, 0, 'MODULE', 'TR', null, null, 1, null, null, null, maxmenuseq.nextval);
commit;

 
3.4.2    配置数据库
3.4.2.1    新建对象
新建对象存储在maximo数据库的MAXOBJECT、MAXOBJECTCFG、MAXTABLE、MAXTABLECFG表中。
注意:服务名、绑定的类名及路径是一一对应的,建议新建的主对象最好都创建自己单独的服务,服务名跟主对象名一样,这样方便每个应用的业务逻辑代码都发布在自己的服务目录下,不是主对象的对象引用现有的服务名,而不重新创建服务。
服务类的创建见2.4.1开发服务类;开发出服务类后在maximo数据库的MAXSERVICE表中配置相应服务,可以使用如下的sql语句:
insert into MAXSERVICE
(servicename,description,classname,maxserviceid) values
('TPRSERVICE','工程项目申请,'com.jxkj.app.tpr.TprService',maxserviceseq.nextval);
或者使用存储过程:
call PAK_TOOL.CofigServiceName('TPR','工程项目申请','com.jxkj.app.tpr.TprService');
MboSet类的创建见2.4.2开发MboSet类;

 
                     图:配置数据库页面

 
                      图:新建数据库对象页面

3.4.2.2    创建对象属性、索引和关系
详见《Maximo620数据库设计指南》文档。
点击“新建行”添加一个新的属性,默认会有***ID(***表示新建的对象名)、description属性(该属性具有长描述,所以还有DESCRIPTION_LONGDESCRIPTION属性);
注:可以参考2.5.1对象属性、关系
1)    对象属性信息存储maxattribute、maxattributecfg表中;
2)    长描述是对某一属性的描述,存储在maximo数据库的maximo.LONGDESCRIPTION表中。当对象的任何一个属性有长描述时,对象具有一个HASLD属性;
3)    对于有状态的mbo必须包括了status和statusdate两个属性;
4)    当对象的级别为Site时,需要两个属性ORGID、SITEID;
5)    需要设置某一属性为自动编号时,勾选“是否能自动编号?”,填写一个自动编号,当填写的自动编号不存在时,会弹出对话框询问是否创建新的自动编号,点击“是”创建,同时默认值填写&AUTOKEY&;自动增长值存储在AUTOKEY表中;
 
                      图:添加属性页面

对象关系属性存储在maximo数据库的MAXRELATIONSHIP表中,注意添加关系时里面条件的写法,比如:tprnum = :tprnum ,前者指的是子对象中的属性,后者指的是当前对象的属性。
也可使用存储过程创建联系:
call PAK_TOOL.createRelation('DOCLINKS','TPR','DOCLINKS','ownertable=''TPR'' and ownerid=:tprid','与 doclink 表相关联');
 
                      图:添加关系信息输入框
3.4.2.3    配置数据库
保存上述所建的对象以及属性、索引、关系,然后关闭weblogic服务器,进入maximo安装目录下的tools/maximo目录,双击configdb.bat,配置数据库,这时maximo程序将在数据库中创建相关的表和关系。
注意:每次修改对象的相关信息或添加、修改属性后都要运行configdb.bat文件配置数据库,添加或修改关系后不用运行configdb.bat。
3.4.3    页面定制
点击转到——配置——应用程序设计器,进入如下图所示应用程序设计器的页面,在该页面中进行页面的设计定制;
 
                  图:应用程序设计器页面
新建应用程序必须指定模块名,指定模块名以及授权后可以在“转到“菜单中链接到自定义的应用程序。
 
         图:创建新应用程序

在应用程序设计器页面中,可以定制页面。页面定制可以采取两种方式:一是在应用程序设计器里画,通过“控制调色板”、“控制属性”、“编辑对话框”三个功能菜单来组装页面;二是先通过应用程序设计器把该APP的XML文件导出来,再在这上面改,改完后再通过应用程序设计器导入数据库。

3.4.4    配置菜单和权限

    file:///C|/Documents and Settings/Administrator/桌面/maximo60开发指南.txt(第 3/24 页)[2010-9-28 9:01:18]

----------------------- Page 4-----------------------

   file:///C|/Documents and Settings/Administrator/桌面/maximo60开发指南.txt

 
 
如上图所示,在选择操作栏选择添加签名选项、操作菜单、工具栏菜单,添加完成后需要授权后用户才能使用指定功能。
 
签名选项存储在maximo数据库的SIGOPTION表中,操作菜单和工具栏菜单存储在maximo数据库的MAXMENU表中,菜单权限存储在maximo数据库的APPLICATIONAUTH表中。
可以使用2.6.2通用菜单的sql语句创建签名选项、菜单和授权(注意:sql语句需要进行适当修改,添加的应用名和描述要改成自己开发应用的名称和描述);

3.5    开发工作流
3.5.1    创建状态表对象
用于记录状态的信息的表,是实际存在于maximo数据库中的表。例如TPRSTATUS。
状态表对象包含属性请参考《Maximo620数据库设计指南》文档。
在主对象中创建与状态对象的关系。
call PAK_TOOL.createRelation('TPRSTATUS','TPR','TPRSTATUS','tprnum = :tprnum and siteid=:siteid','与工程项目申请状态表相关联,用于查找指定工程项目申请的状态记录。结果集将包含一个或多个对象。');
3.5.2    创建虚拟表对象
虚拟表对象是maximo中的一个对象,但在数据库中不存在相应的物理表。
虚拟表对象必须包含属性STATUS、STATDATE、MEMO。
可以使用存储过程较方便地创建虚拟表对象。
call PAK_TOOL.createCSVirtual('TPRCHANGESTATUS','工程项目申请状态更改虚拟表','TPR', 'TPR','com.jxkj.app.tpr.virtual.TprChangeStatusMboSet',1);
3.5.3    创建工作流状态同义词域
同义词域对应工作流中对象的状态;
可以使用2.6.1的sql语句创建同义词域;
创建后使用存储过程为主对象的STATUS字段配置域:
call PAK_TOOL.ConfigDomain('TPR','STATUS','STDSTATUS');
3.5.4    创建操作
操作是工作流程中的辅助选项,通过设置操作可以使流程在运行的过程中完成一些指定的操作,如:设置值、改变状态、操作组、可执行的命令行、定制类、应用程序操作。设置好后的操作由系统自动执行。
操作“设置值”和“改变状态”必须指定对象,而且操作“改变状态”的对象要求是继承stateful的对象即有状态的对象。
在绘制工作流程时可以为流程的每一步指定需要的操作。

点击转到——配置——工作流——操作,进入配置操作的页面。

 
3.5.5    绘制工作流程
图例描述:
图例    名称    描述
     开始节点    一个流程只能有一个开始节点。
     停止节点    一个流程至少有一个停止节点。
     任务节点    可与任务分配者交互的节点,在“任务收件箱”中显示。
     条件判断节点    系统自动根据定义的条件表达式来引导流向或执行操作
     手工节点    提供一个给用户进行选择的交互界面。
     子流程节点    嵌套在父流程中的子流程,子流程结束后返回其父流程的下一个节点。
     交互节点    可以进行两个应用之间的交互。
     等待节点    
 
正向操作    
 
反向操作    

按照业务流程绘制工作流程,配置节点、操作等设置。
点击转到——配置——工作流——工作流设计器,进入工作流设计器,在该页面中绘制工作流和配置节点、操作等设置。
注意:已经激活的工作流程不能再更改,只能创建新的过程修订本 后在新的修订本中进行修改。
简单示例流程:
 
配置节点、操作等设置:
1.开始和结束节点不能改变任何设置;
2.给任务节点分配角色、通讯模板:
任务节点:
     ?    标题:是显示在图标下的文字;描述:是对任务节点的说明;应用程序:是该流程应用的应用程序;时限:是规定该任务需完成的时间长度,超过该时限,则该任务回分配给“升级角色”。
?    任务分配:为该任务分配角色;
?    为角色指定表达式:角色下的表达式可以限制只有在满足该表达式的情况下,任务才会分配到该角色,即同一个任务可以表达式来确定分配对象。该选项对控制转发很有用。
?    执行接受操作,两个选项:接受任务的所有人都接受才算任务接受和只要任何一个人接受就算该任务接受。
?    任务节点可以最多有两个输出操作:一个正向操作和一个反向操作。正向操作对应接受该任务,反向操作对应拒绝该任务。
任务节点的输入操作可以有多个。
3.条件判断节点配置:
条件判断节点:
     ?    标题:是显示在图标下的文字;描述:是对条件节点的说明; 
?    表达式:根据该条件表达式满足与否来控制流程流向。表达式可以根据表达式构建器 来取对象或关系的值作为变量,变量使用的规则是前加“:”。
?    条件判断节点可以最多有两个输出操作:一个正向操作和一个反向操作。正向操作对应满足该表达式的条件,反向操作对应不满足该表达式的条件。
条件判断节点的输入操作可以有多个。
4.手工节点配置:
手工节点:
        ?    标题:是显示在图标下的文字;描述:是对节点的说明; 
?    操作:是根据其输出的操作自动维护;
?    手工节点可以有多个正向输出操作,不能有反向输出操作。
手工节点的输入操作可以有多个。
5.子流程节点配置:
子流程节点:
     ?    标题:是显示在图标下的文字;描述:是对节点的说明; 
?    子过程:是具有和父流程相同对象的流程;
?    子流程节点可以最多有两个输出操作,一个正向输出操作和一个反向输出操作。
子流程节点的输入操作可以有多个。
6.交互节点配置:
交互节点:
        ?    标题:是显示在图标下的文字;描述:是对节点的说明; 
?    应用程序:是该交互节点启用的应用程序,在一个应用中可以发起另外一个应用,其设置就在此处设置;
?    收件人地址标题:在转向应用程序时,弹出的对话框的标题。
?    收件人地址正文:在转向应用程序时,弹出的对话框的内容。
交互节点和条件判断节点进行组合使用,可以达到在某个任务点进行验证信息的目的。
7.操作(连接线)配置:
操作: 
 
 
?    操作:选取2.3.4节创建的操作;描述:是对该连接线的说明; 
表达式:定制执行操作需满足的条件。

3.5.6    验证、启用和激活工作流
 
绘制好后的工作流程必须经过下述过程:
1.验证过程 :系统验证定制的过程是否符合设计规范。
2.启用过程 :使过程能够使用。要使过程处于非启用状态,需先使过程处于非激活状态。如果有父过程引用该过程,则先需使其父过程处于非启用状态。
3.激活过程 :使过程处于活动状态。
4. 添加工作流到应用程序:在应用程序的操作菜单中添加工作流菜单。在此操作后,应用程序的对象会添加如下关系:
关系名    Where子句    子对象    备注:
WFASSIGNMENT    ownertable = 'TPR' and ownerid = :tprid and assignstatus in (select value from synonymdomain where domainid='WFASGNSTATUS' and maxvalue='ACTIVE')    WFASSIGNMENT
    与此 TPR 上的有效任务分配的关系。许多成员集的 (ownertable = 'TPR' and ownerid = :tprid and assignstatus in (select value from synonymdomain where domainid='WFASGNSTATUS' and maxvalue='ACTIVE')) 为零。
WFTOOLBAR    空    WFTOOLBAR    获取管理工具栏按钮的虚拟布景。
WFTRANSACTION    ownertable = 'TPR' and ownerid = :tprid    WFTRANSACTION
    与此 TPR 上工作流交易的关系。许多成员集的 (ownertable = 'TPR' and ownerid = :tprid) 为零。
WORKFLOWMAP    空
    WORKFLOWMAP
    备注:获取虚拟布景以显示过程图。

3.5.7    更改状态的功能设计
更改工作流状态是指在应用程序中提供手动更改状态的功能。具体步骤为:

   file:///C|/Documents and Settings/Administrator/桌面/maximo60开发指南.txt(第 4/24 页)[2010-9-28 9:01:18]

----------------------- Page 5-----------------------

    file:///C|/Documents and Settings/Administrator/桌面/maximo60开发指南.txt

1)    添加签名选项STATUS;
insert into SIGOPTION (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD)
values ('TPR', 'STATUS', '更改状态', 0, 1, null, null, 'SAVE', SIGOPTIONSEQ.NEXTVAL, 'ZH', 0);
2)    添加菜单;
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID)
values ('APPMENU', 'TPR', 9, 1, 'OPTION', 'STATUS', '更改状态', null, 1, 'nav_icon_changestatus.gif', 'CTRL+ALT+A', 'ALL', MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID)
values ('APPTOOL', 'TPR', 30, 0, 'SEP', 'AT30', null, null, 1, null, null, null, MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID)
values ('APPTOOL', 'TPR', 32, 0, 'OPTION', 'STATUS', null, null, 1, 'nav_icon_changestatus.gif', 'CTRL+ALT+A', 'ALL', MAXMENUSEQ.NEXTVAL);
commit;
3)    添加弹出对话框;
 
导出的XML文件:
<dialog id="status" relationship="TPRCHANGESTATUS" savemode="ONLOADUNLOAD" label="更改状态" >
    <section id="changestatus_grid1_1_1_grid3" border="true" datasrc="MAINRECORD" >
      <multiparttextbox id="changestatus_grid1_1_1_grid3_1" dataattribute="tprnum" descdataattribute="description" inputmode="readonly" descinputmode="readonly" />
      <multiparttextbox id="changestatus_grid1_1_1_grid3_5" dataattribute="status" descdataattribute="statusdesc.description" descinputmode="readonly" />
    </section>
    <section id="changestatus_grid1_1_1_grid4" >
      <combobox id="changestatus_grid1_1_1_grid4_1" dataattribute="status" smartfilloff="true" />
      <textbox id="changestatus_grid1_1_1_grid4_2" dataattribute="statdate" lookup="datelookup" />
      <textbox id="changestatus_grid1_1_1_grid4_3" dataattribute="memo" />
    </section>
    <buttongroup id="changestatus_2" >
      <pushbutton id="changestatus_2_1" default="true" mxevent="dialogok" label="确定" />
      <pushbutton id="changestatus_2_2" mxevent="dialogcancel" label="取消" />
    </buttongroup>
  </dialog>
  <dialog id="list_status" relationship="TPRCHANGESTATUS" beanclass="psdi.webclient.beans.common.ChangeStatusBean" savemode="ONUNLOAD" label="更改状态" >
    <section id="list_changestatus_grid1" >
      <sectionrow id="list_changestatus_grid1_1" >
        <sectioncol id="list_changestatus_grid1_1_1" >
          <section id="list_changestatus_grid1_1_1_grid4" >
            <combobox id="list_changestatus_grid1_1_1_grid4_1" dataattribute="status" smartfilloff="true" />
            <textbox id="list_changestatus_grid1_1_1_grid4_2" dataattribute="statdate" lookup="datelookup" />
            <textbox id="list_changestatus_grid1_1_1_grid4_3" dataattribute="Memo" />
          </section>
        </sectioncol>
      </sectionrow>
    </section>
    <buttongroup id="list_changestatus_2" >
      <pushbutton id="list_changestatus_2_1" default="true" mxevent="dialogok" label="确定" />
      <pushbutton id="list_changestatus_2_2" mxevent="dialogcancel" label="取消" />
    </buttongroup>
  </dialog>

4)    增加主对象关系;
 
call PAK_TOOL.createRelation('TPRCHANGESTATUS','TPR','TPRCHANGESTATUS','','与非固定 PRChangeStatus 表相关联。(非固定对象没有 where 子句)。结果集将包含零个或多个对象。注:TPRChangeStatus 是帮助将对话框与对象绑定在一起的非固定 MBO。');
call PAK_TOOL.createRelation('STATUSDESC','TPR','SYNONYMDOMAIN','domainid=''TPRSTATUS'' and value=:status','与 synonymdomain 表相关联 ,用于查找状态的描述,它将包含一个对象。');

5)    授权;
call PAK_TOOL.MenuPriv('TPR','MAXADMIN');
3.6    程序开发
3.6.1    开发服务类
参考2.5.2 服务类源码
?    定义
Maximo把功能类似的一系列的应用归为一个服务,并由统一的类来管理。一个应用程序的所有对象都对应同一个服务。

?    程序实现
1.    创建服务接口
服务接口必须继承psdi.server.AppServiceRemote接口;
2.    创建服务类
服务类必须继承psdi.server.AppService,同时实现创建的服务接口;并且定义如TprService(MXServer mxServer)的带参的构造函数。
注意目前service类中还不写逻辑,只继承超类,由超类来完成其全部实现。创建服务类的目的是方便程序的扩展。
3.6.2    开发MboSet类
参考2.5.3 MboSet类源码
?    定义
MboSet是Maximo中持久层的核心类,其核心的超类psdi.mbo.MboSet。
应用程序对象与MboSet类直接关联,在创建对象时必须指定与对象关联的MboSet类。MboSet类主要用来返回Mbo类的实例。
?    程序实现
MboSet类必须继承psdi.mbo.MboSet类,实现psdi.mbo.MboSetRemote接口;
1)    必须定义如TprMboSet(MboServerInterface arg0)的构造方法;
2)    实现getMboInstance(MboSet arg0)方法,在该方法中返回Mbo类的实例。
3.6.3    开发Mbo类
参考2.5.4 Mbo源码
?    定义
Mbo是Maximo中持久层的核心类,用来处理与数据库的所有操作。其核心的超类是psdi.mbo.Mbo。Mbo类又分为有状态的Mbo和无状态的Mbo。无状态的Mbo的例子为psdi.mbo.custapp.CustomMbo和psdi.mbo.custapp.CustomMboSet,不考虑应用中状态的变化,所有新建的对象都会使用这个Mbo。而一个有状态的Mbo,如工单,是会发生自己的变化的,系统中没有提供新建一个有状态的Mbo的功能,目前必须自定义。

?    程序实现
以下介绍有状态Mbo类的实现。
有状态Mbo类必须继承psdi.mbo.StatefulMbo类,实现psdi.mbo.StatefulMboRemote接口。
1)    必须定义如TprMbo(MboSet arg0)的构造方法;
2)    实现getStatusHandler()方法,在该方法中返回自定义StatusHandler类的实例;
3)    实现getStatusHistory()方法,在该方法中返回主对象与关系对象的关系名称;
4)    实现getStatusListName()方法,在该方法中返回一个定义好的状态synonym域的名称。如:WOSTATUS;

3.6.4    开发StatusHandler类
参考2.5.5 StatusHandler源码
?    定义
该类用于工作流中更改状态。

?    程序实现
StatusHandler必须继承psdi.mbo.StatusHandler类。
1)必须定义如TprStatusHandler(StatefulMbo sm)的构造方法
并覆写如下两个方法:checkStatusChangeAuthorization(String s),
changeStatus(String s, String s1, Date date, String s2):用来做状态的改变。

3.6.5    编译
将程序编译后放在maximo部署目录的businessobjects.jar目录下。
RMI编译只需使用1.2版即可,即只需生存存根*_Stub.classes即可。
需要进行RMI编译的包括扩展的Mbo、MboSet、AppService。
3.7    源码参考
以下对象属性、关系及程序源码仅供参考。
3.7.1    对象属性、关系
1)主表对象属性
 
2)状态表对象属性
 
3)虚拟表对象属性
 
4)主表关系

    file:///C|/Documents and Settings/Administrator/桌面/maximo60开发指南.txt(第 5/24 页)[2010-9-28 9:01:18]

----------------------- Page 6-----------------------

     file:///C|/Documents and Settings/Administrator/桌面/maximo60开发指南.txt

 
3.7.2    服务类
服务接口ITprService
package com.jxkj.app.tpr;

import psdi.server.AppServiceRemote;

public interface ITprService extends AppServiceRemote
{

}
服务类
package com.jxkj.app.tpr;

import java.rmi.RemoteException;

import psdi.server.AppService;
import psdi.server.MXServer;

public class TprService extends AppService implements ITprService
{
    public TprService() throws RemoteException
    {
    super();
    }

    public TprService(MXServer mxServer) throws RemoteException
    {
    super(mxServer);
    }

}

3.7.3    MboSet类
1)主对象MboSet
package com.jxkj.app.tpr;

import java.rmi.RemoteException;

import psdi.mbo.Mbo;
import psdi.mbo.MboServerInterface;
import psdi.mbo.MboSet;
import psdi.mbo.MboSetRemote;
import psdi.util.MXException;

public class TprMboSet extends MboSet implements MboSetRemote
{

    public TprMboSet(MboServerInterface mboserverinterface) throws MXException, RemoteException
    {
    super(mboserverinterface);
    }

    protected Mbo getMboInstance(MboSet ms) throws MXException, RemoteException
    {
    return new TprMbo(ms);
    }

}

2)状态对象MboSet
package com.jxkj.app.tpr;

import java.rmi.RemoteException;

import psdi.mbo.Mbo;
import psdi.mbo.MboServerInterface;
import psdi.mbo.MboSet;
import psdi.mbo.MboSetRemote;
import psdi.util.MXException;

public class TprStatusMboSet extends MboSet implements MboSetRemote
{
    public TprStatusMboSet(MboServerInterface ms) throws RemoteException
    {
    super(ms);
    }

    protected Mbo getMboInstance(MboSet ms) throws MXException, RemoteException
    {
    return new TprStatusMbo(ms);
    }

}

虚拟表对象MboSet
package com.jxkj.app.tpr.virtual;

import java.rmi.RemoteException;

import psdi.app.common.virtual.ChangeStatusSet;
import psdi.mbo.Mbo;
import psdi.mbo.MboRemote;
import psdi.mbo.MboServerInterface;
import psdi.mbo.MboSet;
import psdi.mbo.MboSetRemote;
import psdi.mbo.NonPersistentMboSetRemote;
import psdi.mbo.SqlFormat;
import psdi.util.MXException;

import com.jxkj.app.tpr.TprMbo;

public class TprChangeStatusMboSet extends ChangeStatusSet implements NonPersistentMboSetRemote
{

    public TprChangeStatusMboSet(MboServerInterface ms) throws MXException, RemoteException
    {
    super(ms);
    }
    
    // 返回Mbo实例
    protected Mbo getMboInstance(MboSet ms) throws MXException, RemoteException

     file:///C|/Documents and Settings/Administrator/桌面/maximo60开发指南.txt(第 6/24 页)[2010-9-28 9:01:18]

----------------------- Page 7-----------------------

      file:///C|/Documents and Settings/Administrator/桌面/maximo60开发指南.txt

    {
    return new TprChangeStatusMbo(ms);
    }

    protected MboSetRemote getMboIntoSet(MboRemote mbo) throws MXException, RemoteException
    {

    MboSetRemote changeWOSet = getMboServer().getMboSet("TPR", getUserInfo());
    SqlFormat sqf = new SqlFormat(mbo, "tprnum = :tprnum and siteid = :siteid");
    changeWOSet.setWhere(sqf.format());
    return changeWOSet;
    }

    protected void changeMboStatus(MboRemote tpr, MboRemote param) throws MXException, RemoteException
    {
    ((TprMbo) tpr).changeStatus(param.getString("status"), param.getDate("statdate"), param.getString("memo"));
    }

3.7.4    Mbo类
1)    主对象Mbo
package com.jxkj.app.tpr;

import java.rmi.RemoteException;
import java.util.Date;
import java.util.HashSet;

import psdi.mbo.MboRemote;
import psdi.mbo.MboSet;
import psdi.mbo.MboSetRemote;
import psdi.mbo.MboValueInfo;
import psdi.mbo.StatefulMbo;
import psdi.mbo.StatusHandler;
import psdi.server.AppService;
import psdi.util.MXException;

public class TprMbo extends StatefulMbo implements MboRemote

{
    private static HashSet skipFieldCopy = new HashSet();

    private static boolean isHashSetLoaded = false;

    public TprMbo(MboSet ms) throws MXException, RemoteException
    {
    super(ms);
    }

    // 返回工作流名称
    public String getProcess()
    {
    return "TPR";
    }

    protected StatusHandler getStatusHandler()
    {
    // 返回状态处理的类
    return new TprStatusHandler(this);
    }

    // 返回主对象与关系对象的关系名称
    protected MboSetRemote getStatusHistory() throws MXException, RemoteException
    {
    return this.getMboSet("TPRSTATUS");
    }

    // 返回状态的值列表名称
    public String getStatusListName()
    {
    return "STDSTATUS";
    }

    /**
         * 新增
         * 
         * @throws MXException
         * @throws RemoteException
         */
    public void add() throws MXException, RemoteException
    {

    super.add();
    Date currentDate = ((AppService)getMboServer()).getMXServer().getDate();
    setValue("historyflag", false, NOACCESSCHECK| NOVALIDATION);
    setValue("status", getTranslator().toExternalDefaultValue("STDSTATUS", "WAPPR", this), NOACCESSCHECK| NOVALIDATION);
    setValue("statusdate", currentDate, NOACCESSCHECK| NOVALIDATION);
        setValue("Requestby", getUserInfo().getUserName(), NOACCESSCHECK| NOVALIDATION);
        setValue("RequestDate", currentDate, NOACCESSCHECK| NOVALIDATION);
    }

    public MboRemote duplicate() throws MXException, RemoteException
    {
    if (!isHashSetLoaded)
        loadSkipFieldCopyHashSet();
    MboRemote newTestRemote = copy();
    MboSetRemote myDoclinksSetRemote = getMboSet("DOCLINKS");
    myDoclinksSetRemote.copy(newTestRemote.getMboSet("DOCLINKS"));
    return newTestRemote;
    }

    private static void loadSkipFieldCopyHashSet() throws MXException, RemoteException
    {
    isHashSetLoaded = true;
    skipFieldCopy.add("TRPNUM");
    skipFieldCopy.add("STATUS");
    skipFieldCopy.add("STATUSDATE");
    skipFieldCopy.add("REQUESTBY");
    skipFieldCopy.add("REQUESTDATE");
    skipFieldCopy.add("ORGID");
    skipFieldCopy.add("SITEID");
    }

      file:///C|/Documents and Settings/Administrator/桌面/maximo60开发指南.txt(第 7/24 页)[2010-9-28 9:01:18]

----------------------- Page 8-----------------------

      file:///C|/Documents and Settings/Administrator/桌面/maximo60开发指南.txt

    protected boolean skipCopyField(MboValueInfo mvi) throws MXException, RemoteException
    {
    return skipFieldCopy.contains(mvi.getName());
    }

}

2)    状态对象Mbo
package com.jxkj.app.tpr;

import java.rmi.RemoteException;

import psdi.mbo.Mbo;
import psdi.mbo.MboRemote;
import psdi.mbo.MboSet;
import psdi.util.MXApplicationException;
import psdi.util.MXException;

public class TprStatusMbo extends Mbo implements MboRemote
{

    public TprStatusMbo(MboSet ms) throws RemoteException
    {
    super(ms);
    }

    // 把状态记录写入状态表中
    public void add() throws MXException, RemoteException
    {
    MboRemote owner = getOwner();

    if (owner == null || !owner.getName().equals("TPR"))
    {
        throw new MXApplicationException("tpr", "addstatus");
    }
    else
    {
        setValue("tprnum", owner.getString("tprnum"), NOACCESSCHECK);
        setValue("status", owner.getString("status"), NOACCESSCHECK);
        setValue("changedate", owner.getDate("statusdate"), NOACCESSCHECK);
        return;
    }
    }

}

3)    虚拟表对象Mbo
package com.jxkj.app.tpr.virtual;

import java.rmi.RemoteException;

import psdi.mbo.MboSet;
import psdi.mbo.NonPersistentMbo;
import psdi.mbo.NonPersistentMboRemote;
import psdi.server.MXServer;
import psdi.util.MXException;

public class TprChangeStatusMbo extends NonPersistentMbo implements NonPersistentMboRemote
{

    public TprChangeStatusMbo(MboSet ms) throws MXException, RemoteException
    {
    super(ms);
    }

    public void add() throws MXException, RemoteException
    {
    super.add();
    java.util.Date currentDT = MXServer.getMXServer().getDate();
    setValue("statdate", currentDT, NOACCESSCHECK | NOVALIDATION);
    }
}

3.7.5    StatusHandler类
package com.jxkj.app.tpr;

import java.rmi.RemoteException;
import java.util.Date;

import psdi.mbo.StatefulMbo;
import psdi.mbo.StatusHandler;
import psdi.security.ProfileRemote;
import psdi.util.MXAccessException;
import psdi.util.MXApplicationException;
import psdi.util.MXException;

public class TprStatusHandler extends StatusHandler
{

    private StatefulMbo parent;

    private String WAPPR;

    private String APPROVE;

    private String CLOSE;

    private String CANCEL;

    private String INPRG;

    static final int Wappr = 0;

    static final int Appr = 1;

    static final int Close = 2;

    static final int Can = 3;

      file:///C|/Documents and Settings/Administrator/桌面/maximo60开发指南.txt(第 8/24 页)[2010-9-28 9:01:18]

----------------------- Page 9-----------------------

      file:///C|/Documents and Settings/Administrator/桌面/maximo60开发指南.txt

    static final int Inprg = 4;

    public TprStatusHandler(StatefulMbo sm)
    {
    super(sm);
    parent = null;
    WAPPR = "WAPPR";
    APPROVE = "APPR";
    CLOSE = "CLOSE";
    CANCEL = "CAN";
    INPRG = "INPRG";
    parent = sm;
    }

    static int convertStatusToInt(String internalStatus)
    {
    if (internalStatus.equalsIgnoreCase("WAPPR"))
        return 0;
    if (internalStatus.equalsIgnoreCase("APPR"))
        return 1;
    if (internalStatus.equalsIgnoreCase("CLOSE"))
        return 2;
    if (internalStatus.equalsIgnoreCase("INPRG"))
        return 4;
    return !internalStatus.equalsIgnoreCase("CAN") ? -1 : 3;

    }

    public void checkStatusChangeAuthorization(String desiredExternalStatus) throws MXException, RemoteException
    {
    String desiredMaxStatus = parent.getTranslator().toInternalString("STDSTATUS", desiredExternalStatus);
    checkUserSecurity(desiredMaxStatus);

    }

    public void checkUserSecurity(String desiredMaxStatus) throws MXException, RemoteException
    {
    String application = parent.getThisMboSet().getApp();
    if (application == null || application.equals(""))
        return;
    String optionName = null;
    if (desiredMaxStatus.equals("WAPPR"))
        optionName = "UNAPPROVE";
    else if (desiredMaxStatus.equals("APPR"))
        optionName = "APPROVE";
    else if (desiredMaxStatus.equals("CAN"))
        optionName = "CANCEL";
    else if (desiredMaxStatus.equals("CLOSE"))
        optionName = "CLOSE";
    else if (desiredMaxStatus.equals("INPRG"))
        optionName = "INPRG";
    ProfileRemote p = parent.getMboServer().getProfile(parent.getUserInfo());
    if (optionName == null || !p.getAppOptionAuth(application, optionName, parent.getString("siteid")))
        throw new MXAccessException("access", "notauthorized");
    else
        return;
    }

    // 更改工作流中的状态
    public void changeStatus(String currentStatus, String desiredStatus, Date date, String memo) throws MXException,
        RemoteException
    {
    if (date.getTime() < parent.getDate("statusdate").getTime())
        throw new MXApplicationException("tpr", "statusdate");
    String currentMaxStatus = parent.getTranslator().toInternalString("STDSTATUS", currentStatus);
    String desiredMaxStatus = parent.getTranslator().toInternalString("STDSTATUS", desiredStatus);
    if (desiredMaxStatus.equals(WAPPR))
        unapprove(currentMaxStatus, desiredStatus);
    else if (desiredMaxStatus.equals(APPROVE))
        approve(currentMaxStatus, desiredStatus);
    else if (desiredMaxStatus.equals(CLOSE))
        close(currentMaxStatus, desiredStatus);
    else if (desiredMaxStatus.equals(CANCEL))
        cancel(currentMaxStatus, desiredStatus);
    parent.setValue("statusdate", date, NOACCESSCHECK);
    }

    private void approve(String currentMaxStatus, String desiredStatus) throws MXException, RemoteException
    {
    parent.setValue("status", desiredStatus, NOACCESSCHECK);
    }

    private void unapprove(String currentMaxStatus, String desiredStatus) throws MXException, RemoteException
    {
    parent.setValue("status", desiredStatus, NOACCESSCHECK);
    }

    private void cancel(String currentMaxStatus, String desiredStatus) throws MXException, RemoteException
    {
    parent.setValue("historyflag", true, NOACCESSCHECK);
    parent.setValue("status", desiredStatus, NOACCESSCHECK);
    }

    private void close(String currentMaxStatus, String desiredStatus) throws MXException, RemoteException
    {
    parent.setValue("historyflag", true, NOACCESSCHECK);
    parent.setValue("status", desiredStatus, NOACCESSCHECK);
    }
}
 

3.8    How do….
3.8.1    移植工具介绍
移植工具,请使用健新自行开发的移植工具,可以从你的项目经理处取得此移植工具。
移植工具:
Sql:导出工具名称。
Sqlhelp:导出工具的帮助。
使用示例:
sql app=estimate tables="(estimate,estimateline,estimatestatus,cestimatestatus)" workflow="(estimate.1)" file=.\sql\estimate\estimate_app.sql
注:由于Maximo6.2.1中无法获得应用程序所关联的表的名称,所以表名需要你自己写出来了。
注:由一组织机构或地点导出来的应用程序,不能直接导入到另一组织机构或地点使用,需要做一下小小的修改,更改autokey中的组织机构或地点的值即可。例:update autokey set orgid='HHPSPB' where orgid='HLTS';
3.8.2    非工作流应用程序必须的关系

      file:///C|/Documents and Settings/Administrator/桌面/maximo60开发指南.txt(第 9/24 页)[2010-9-28 9:01:18]

----------------------- Page 10-----------------------

    file:///C|/Documents and Settings/Administrator/桌面/maximo60开发指南.txt

非工作流一定需要建立的关系(不包括建表时,自动建立的),参考如下:
--与附加文档之间的关系
call PAK_TOOL.createRelation('DOCLINKS','ABNORMITY','DOCLINKS','ownertable=''ABNORMITY'' and ownerid=:abnormityid','与 doclink 表相关联');

3.8.3    工作流应用程序必须的关系
工作流一定需要建立的关系(不包括建表时,自动建立的),参考示例:
call PAK_TOOL.createRelation('DOCLINKS','ESTIMATE','DOCLINKS','ownertable=''ESTIMATE'' and ownerid=:estimateid','与 doclink 表相关联');
call PAK_TOOL.createRelation('ESTIMATESTATUS','ESTIMATE','ESTIMATESTATUS','estimatenum=:estimatenum and siteid = :siteid','评级主表与状态表的关联');
call PAK_TOOL.createRelation('CESTIMATESTATUS','ESTIMATE','CESTIMATESTATUS','','评级主表与状态虚拟表的关联,用于更改状态页面');
call PAK_TOOL.createRelation(' SYNONYMDOMAIN','ESTIMATE','SYNONYMDOMAIN','domainid=''STDSTATUS'' and value=:status','与 synonymdomain 表相关联,用于查找状态的描述,它将包含一个对象。');
call PAK_TOOL.createRelation('ESTIMATESTATUSBY','ESTIMATESTATUS','PERSON','personid=:changeby','与 PERSON 表相关联');

3.8.4    将工作流状态显示中文
只需建立一个联系即可。联系名称一般取:SYNONYMDOMAIN。
例:与工单状态建立的联系方式:
call PAK_TOOL.createRelation('SYNONYMDOMAIN','WorkOrder','SYNONYMDOMAIN','domainid=''WOSTATUS'' and value=:status','与 SYNONYMDOMAIN 表相关联');
使用方法:SYNONYMDOMAIN.DESCRIPTION
3.8.5    位置编号选择
如果你的应用程序中需要与位置进行关联,则可以使用默认的类(当然你也可以扩展此类):
call PAK_TOOL.CofigColClassName('ESTIMATELINE','LOCATION','psdi.app.location.FldLocation');
以下关系是与位置关联必须要建立的:
call PAK_TOOL.createRelation('DRILLDOWN','ESTIMATELINE','DRILLDOWN','','资产与位置需要用的关联');

3.8.6    资产编号选择
如果你的应用程序中需要与资产进行关联,则可以使用默认的类(当然你也可以扩展此类),示例如下:
call PAK_TOOL.CofigColClassName('ESTIMATELINE','ASSETNUM','psdi.app.asset.FldAssetnum');
以下关系是与资产关联必须要建立的:
call PAK_TOOL.createRelation('DRILLDOWN','ESTIMATELINE','DRILLDOWN','','资产与位置需要用的关联');
call PAK_TOOL.createRelation('VIEWCONTINPUT','ESTIMATELINE','VIEWCONTINPUT','','在资产中,选择查看合同的联系名');

3.8.7    人员编号选择
call PAK_TOOL.CofigColClassName('WorkOrder','DUTY','psdi.app.person.FldPersonID');
3.8.8    人员组编号选择
与人员组关联,可以使用默认类(当然你也可以扩展此类),参考示例:
call PAK_TOOL.CofigColClassName('ESTIMATE','PERSONGROUP','psdi.app.persongroup.FldPersonGroup');

3.8.9    工作流的标准状态
使用2.8.1的SQL语句执行即可。
3.8.10    添加额外菜单
一般非工作流中需要添加归档(ARCHIVING)、编辑历史(EDITHIST),两个菜单。工作流应用中需要添加查看历史(VIEWHIST)、更改状态(STATUS)、编辑历史(EDITHIST)。
其中归档与编辑历史需要继承AppBean类,自己写方法,方法名与菜单名一样全大写,即可。示例如下:
 
以上类需要在xml中注册:
 
更改状态、查看历史需要在XML中添加3个dialog(status、list_status、viewhist)。参考示例如下(可以参考采购申请PR):
 
3.8.11        一般应用程序需要包括的类
示例的相关信息:
1、    应用程序名:abnormity(设备异动)
2、    应用程序表:abnormity(主表)
类名    示例    说明
AppServiceRemote    com.jxkj.app.abnormity.AbnormitServiceRemote    可省略,RMI
AppService    com.jxkj.app.abnormity.AbnormitService    可省略,RMI
MboRemote    com.jxkj.app.abnormity.AbnormitRemote    可省略,RMI
Mbo    com.jxkj.app.abnormity    RMI
MboSetRemote    com.jxkj.app.abnormity.AbnormitSetRemote    可省略,RMI
MboSet    com.jxkj.app.abnormity.AbnormitSet    RMI
AppBean    com.jxkj.webclient.beans.abnormity. AbnormityAppBean    WEB页面

3.8.12    工作流应用程序需要包括的类
示例的相关信息:
3、    应用程序名:Estimate(设备评级)
4、    应用程序表:Estimate(主表)、EstimateStatus(状态表)、CEstimateStatus(虚拟表)、EstimateLine(细表)
类名    示例    说明
AppServiceRemote    com.jxkj.app.estimate.AppserviceRemote    可省略,RMI
AppService    com.jxkj.app.estimate.Appservice    可省略,RMI
MboRemote    com.jxkj.app.estimate.EstimateRemote    可省略,RMI
Mbo    com.jxkj.app.estimate.Estimate    RMI
MboSetRemote    com.jxkj.app.estimate.EstimateSetRemote    可省略,RMI
MboSet    com.jxkj.app.estimate.EstimateSet    RMI
MboRemote    com.jxkj.app.estimate.EstimateLineRemote    可省略,RMI
Mbo    com.jxkj.app.estimate.EstimateLine    RMI
MboSetRemote    com.jxkj.app.estimate.EstimateLineSetRemote    可省略,RMI
MboSet    com.jxkj.app.estimate.EstimateLineSet    RMI
MboRemote    com.jxkj.app.estimate.EstimateStatusRemote    可省略,RMI
Mbo    com.jxkj.app.estimate.EstimateStatus    RMI
MboSetRemote    com.jxkj.app.estimate.EstimateStatusRemote    可省略,RMI
MboSet    com.jxkj.app.estimate.EstimateStatusSet    RMI
MboRemote        可省略,RMI
Mbo    com.jxkj.app.estimate.virtual.CEstimateStatus    RMI
MboSetRemote        可省略,RMI
MboSet    com.jxkj.app.estimate.virtual.CEstimateStatusSet    RMI
AppBean    com.jxkj.webclient.beans.estimate. EstimateAppBean    WEB页面

3.8.13    系统XML文件说明
在应用程序设计器中可以导出系统XML文件,系统XML文件如下图:
 
    输入控件参考如下:
 
7、    Lookups为具体输入控件中的lookup提供支持。
8、    Menus为具体输入控件中的menutype提供支持。
9、    Library为Menus中定义的菜单提供支持。
10、    RepLibrary为报表提供支持。
11、    ToolBox

3.8.14    下载乱码
版本6.2.1,下载时出现乱码,需将下载的JSP页面添加GB2312字符,6.2.0中是修改为GBK字符集。

在maximo62的列表界面使用下载功能,下载的excel文件经常有乱码,解决办法: 
1、 修改maximo\maximouiweb.war\webclient\controls\table\download.jsp 
将response.setContentType("application/vnd.ms-excel ");
改为 response.setContentType("application/vnd.ms-excel;charset=gb2312 "); 有两处需要修改。 
2、 重启weblogic就OK了

3.8.15    数据备份/恢复
1、    备份
set NLS_LANG=AMERICAN_AMERICA.AL32UTF8
exp maximo/maximo@maximo file=C:\maximo621.dmp log=C:\maximo621.log
2、    恢复
set NLS_LANG=AMERICAN_AMERICA.AL32UTF8
imp maximo/maximo@maximo file=C:\maximo621.dmp log=C:\maximo621.log full=y ignore=y

    file:///C|/Documents and Settings/Administrator/桌面/maximo60开发指南.txt(第 10/24 页)[2010-9-28 9:01:18]

----------------------- Page 11-----------------------

    file:///C|/Documents and Settings/Administrator/桌面/maximo60开发指南.txt

3.8.16    无法准确移动至、、、
当转至到、、、无法准确定位时,由于所转到的表的当前字段的搜索类型是WILDCARD(通配符搜索),需改为EXACT(精确匹配)即可。
例:在6.2.1中,资产的分类无法准确定位,执行以下SQL语句即可。
call PAK_TOOL.ConfigColSearchType('classstructure','classstructureid','EXACT');

3.8.17    为什么不能在快速查找中输入单号
为什么不能在 输入单号查询呢?请将XXNUM和SITEID字段设定为主列XXID不要设为主列。设定了主列之后,系统自动可以保证单号不重复。
3.8.18    应用程序更改模块名
select * from maxmenu where  elementtype='APP' and keyvalue='应用程序名字';
更改模块名的方法:
update maxmenu set moduleapp=?,position=?  where  elementtype='APP' and keyvalue=
注:position一定要大于模块的position。
3.8.19    为什么有时模糊查询,查不到结果
select * from compmaster where (companysetid = 'HLCOM' and contains(name,'$备') > 0 ) 
select * from compmaster where (companysetid = 'HLCOM' and contains(name,'$设备') > 0 )
以上这两条SQL语句,第二条查询的结果比第一条多,这是因为采用了文本搜索技术,此技术在Maximo中应用是通过词根来搜索,但这东东对中文支持并不是很好,所以不建议采用文本搜索,具体参看GOOGLE之ORACLE的TEXT搜索技术。

3.8.20    如何添加外部网址链接
在maxmenu表的字段url中指定要链接的网址即可。
例如:要在点击某个应用时转到指定网址,在maxmenu表该应用记录的url字段写明网址即可,这样点击该应用时不会进入maximo的页面,而是跳转到指定链接页面。
注意:添加应用的链接时,该应用必须存在于maxapps表中;
添加菜单的链接时,菜单必须存在于sigoption表中;
用户必须有应用或菜单的读的权限,才可以点击应用或菜单。
3.9    附录
3.9.1    创建状态同义词域的sql语句
1)在MAXDOMAIN表中添加记录:
insert into MAXDOMAIN (DOMAINID, DESCRIPTION, DOMAINTYPE, MAXTYPE, LENGTH, SCALE, MAXDOMAINID)
values ('STDSTATUS', '标准工作流状态', 'SYNONYM', 'UPPER', 10, 0, maxdomainseq.nextval);
2)在SYNONYMDOMAIN表中添加记录:
同义词域的每一个状态在SYNONYMDOMAIN表中对应一条记录。
insert into SYNONYMDOMAIN (DOMAINID, MAXVALUE, VALUE, DESCRIPTION, DEFAULTS, SITEID, ORGID, SYNONYMDOMAINID)
values ('STDSTATUS', 'APPR', 'APPR', '已批准', 1, null, null, synonymdomainseq.nextval);
insert into SYNONYMDOMAIN (DOMAINID, MAXVALUE, VALUE, DESCRIPTION, DEFAULTS, SITEID, ORGID, SYNONYMDOMAINID)
values ('STDSTATUS', 'CAN', 'CAN', '已取消', 1, null, null, synonymdomainseq.nextval);
insert into SYNONYMDOMAIN (DOMAINID, MAXVALUE, VALUE, DESCRIPTION, DEFAULTS, SITEID, ORGID, SYNONYMDOMAINID)
values ('STDSTATUS', 'CLOSE', 'CLOSE', '关闭', 1, null, null, synonymdomainseq.nextval);
insert into SYNONYMDOMAIN (DOMAINID, MAXVALUE, VALUE, DESCRIPTION, DEFAULTS, SITEID, ORGID, SYNONYMDOMAINID)
values ('STDSTATUS', 'WAPPR', 'WAPPR', '等待批准', 1, null, null, synonymdomainseq.nextval);
insert into SYNONYMDOMAIN (DOMAINID, MAXVALUE, VALUE, DESCRIPTION, DEFAULTS, SITEID, ORGID, SYNONYMDOMAINID)
values ('STDSTATUS', 'INPRG', 'INPRG', '进行中', 1, null, null, synonymdomainseq.nextval);

3.9.2    通用菜单sql语句
//签名选项模板(用于创建签名选项)
insert into SIGOPTION (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD)
values ('TPR', 'READ', '读取工程项目申请', 0, 1, 'CLEAR, NEXT, PREVIOUS, BOOKMARK', 'ALL', null, SIGOPTIONSEQ.NEXTVAL , 'ZH', 0);
insert into SIGOPTION (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD)
values ('TPR', 'CREATEKPI', '创建 KPI', 0, 1, null, null, 'READ', SIGOPTIONSEQ.NEXTVAL, 'ZH', 0);
insert into SIGOPTION (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD)
values ('TPR', 'DELETE', '删除工程项目申请', 0, 1, null, null, 'READ', SIGOPTIONSEQ.NEXTVAL, 'ZH', 0);
insert into SIGOPTION (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD)
values ('TPR', 'SEARCHWHER', 'Where 子句', 0, 1, null, null, 'READ', SIGOPTIONSEQ.NEXTVAL, 'ZH', 0);
insert into SIGOPTION (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD)
values ('TPR', 'FIELDDEFS', '设置字段默认值', 0, 0, null, null, 'SAVE', SIGOPTIONSEQ.NEXTVAL, 'ZH', 0);
insert into SIGOPTION (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD)
values ('TPR', 'SEARCHSQRY', '保存当前查询', 0, 1, null, null, 'READ', SIGOPTIONSEQ.NEXTVAL, 'ZH', 0);
insert into SIGOPTION (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD)
values ('TPR', 'BOOKMARK', '添加到书签', 0, 0, null, null, 'READ', SIGOPTIONSEQ.NEXTVAL, 'ZH', 0);
insert into SIGOPTION (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD)
values ('TPR', 'RUNREPORTS', '运行报表', 0, 1, null, null, 'READ', SIGOPTIONSEQ.NEXTVAL, 'ZH', 0);
insert into SIGOPTION (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD)
values ('TPR', 'DUPLICATE', '复制工程项目申请', 0, 1, null, null, 'INSERT', SIGOPTIONSEQ.NEXTVAL, 'ZH', 0);
insert into SIGOPTION (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD)
values ('TPR', 'INSERT', '新建工程项目申请', 0, 1, 'SAVE', 'DUPLICATE', 'READ', SIGOPTIONSEQ.NEXTVAL, 'ZH', 0);
insert into SIGOPTION (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD)
values ('TPR', 'NEXT', '下一工程项目申请', 0, 0, null, null, 'READ', SIGOPTIONSEQ.NEXTVAL, 'ZH', 0);
insert into SIGOPTION (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD)
values ('TPR', 'PREVIOUS', '上一工程项目申请', 0, 0, null, null, 'READ', SIGOPTIONSEQ.NEXTVAL, 'ZH', 0);
insert into SIGOPTION (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD)
values ('TPR', 'SAVE', '保存工程项目申请', 0, 1, null, 'INSERT, DUPLICATE, FIELDDEFS', 'READ', SIGOPTIONSEQ.NEXTVAL, 'ZH', 0);
insert into SIGOPTION (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD)
values ('TPR', 'CLEAR', '清除更改', 0, 0, null, null, 'READ', SIGOPTIONSEQ.NEXTVAL, 'ZH', 0);
insert into SIGOPTION (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD)
values ('TPR', 'SEARCHMORE', '更多搜索字段', 0, 1, null, null, 'READ', SIGOPTIONSEQ.NEXTVAL, 'ZH', 0);
insert into SIGOPTION (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD)
values ('TPR', 'SEARCHBOOK', '书签', 0, 1, null, null, 'READ', SIGOPTIONSEQ.NEXTVAL, 'ZH', 0);
insert into SIGOPTION (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD)
values ('TPR', 'SEARCHVMQR', '查看/管理查询', 0, 1, null, null, 'READ', SIGOPTIONSEQ.NEXTVAL, 'ZH', 0);
insert into SIGOPTION (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD)
values ('TPR', 'MANAGELIB', '管理库', 0, 1, null, null, 'READ', SIGOPTIONSEQ.NEXTVAL, 'ZH', 0);
insert into SIGOPTION (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD)
values ('TPR', 'MANAGEFOLD', '管理文件夹', 0, 1, null, null, 'READ', SIGOPTIONSEQ.NEXTVAL, 'ZH', 0);
insert into SIGOPTION (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD)
values ('TPR', 'ASSOCFOLD', '相关文件夹', 0, 1, null, null, 'READ', SIGOPTIONSEQ.NEXTVAL, 'ZH', 0);
insert into SIGOPTION (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD)
values ('TPR', 'SEARCHTIPS', '查看搜索提示', 0, 1, null, null, 'READ', SIGOPTIONSEQ.NEXTVAL, 'ZH', 0);

//菜单模板(用于创建菜单) 
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID)
values ('APPMENU', 'TPR', 33, 0, 'OPTION', 'BOOKMARK', null, null, 1, null, null, 'MAIN',  MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID)
values ('APPMENU', 'TPR', 9001, 0, 'OPTION', 'RUNREPORTS', null, null, 1, null, null, 'ALL',  MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID)
values ('APPMENU', 'TPR', 31, 0, 'OPTION', 'DUPLICATE', null, null, 1, null, null, 'MAIN',  MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID)
values ('APPMENU', 'TPR', 9000, 0, 'SEP', 'AM9000', null, null, 1, null, null, null,  MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID)
values ('APPMENU', 'TPR', 32, 0, 'OPTION', 'DELETE', null, null, 1, null, null, 'MAIN',  MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID)
values ('APPTOOL', 'TPR', 12, 0, 'OPTION', 'INSERT', null, null, 1, 'nav_icon_insert.gif', 'CTRL+ALT+I', 'ALL',  MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID)
values ('APPTOOL', 'TPR', 23, 0, 'OPTION', 'NEXT', null, null, 1, 'nav_icon_next.gif', 'CTRL+ALT+N', 'MAIN',  MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID)
values ('APPTOOL', 'TPR', 22, 0, 'OPTION', 'PREVIOUS', null, null, 1, 'nav_icon_previous.gif', 'CTRL+ALT+P', 'MAIN', MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID)
values ('APPTOOL', 'TPR', 13, 0, 'OPTION', 'SAVE', null, null, 1, 'nav_icon_save.gif', 'CTRL+ALT+S', 'MAIN',  MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID)
values ('APPTOOL', 'TPR', 14, 0, 'OPTION', 'CLEAR', null, null, 1, 'nav_icon_clear.gif', 'CTRL+ALT+C', 'MAIN',  MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID)
values ('APPTOOL', 'TPR', 20, 0, 'SEP', 'AT20', null, null, 1, null, null, null,  MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID)
values ('APPTOOL', 'TPR', 40, 0, 'SEP', 'AT40', null, null, 1, null, null, null,  MAXMENUSEQ.NEXTVAL);

    file:///C|/Documents and Settings/Administrator/桌面/maximo60开发指南.txt(第 11/24 页)[2010-9-28 9:01:18]

----------------------- Page 12-----------------------

    file:///C|/Documents and Settings/Administrator/桌面/maximo60开发指南.txt

insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID)
values ('SEARCHMENU', 'TPR', 20, 10, 'OPTION', 'SEARCHSQRY', null, null, 1, null, null, 'ALL', MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID)
values ('APPTOOL', 'TPR', 100, 0, 'SEP', 'AT100', null, null, 1, null, null, null,  MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID)
values ('SEARCHMENU', 'TPR', 10, 20, 'OPTION', 'SEARCHWHER', null, null, 1, null, null, 'ALL',  MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID)
values ('APPMENU', 'TPR', 20, 0, 'SEP', 'AM20', null, null, 1, null, null, null,  MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID)
values ('SEARCHMENU', 'TPR', 10, 0, 'HEADER', 'SM10', '高级搜索', null, 1, 'atb_search.gif', null, 'ALL',  MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID)
values ('SEARCHMENU', 'TPR', 30, 0, 'OPTION', 'SEARCHBOOK', null, null, 1, 'atb_bookmark.gif', null, 'ALL',  MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID)
values ('APPMENU', 'TPR', 18, 20, 'OPTION', 'MANAGEFOLD', null, null, 1, null, null, 'ALL',  MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID)
values ('APPMENU', 'TPR', 18, 30, 'OPTION', 'ASSOCFOLD', null, null, 1, null, null, 'ALL',  MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID)
values ('APPMENU', 'TPR', 17, 0, 'SEP', 'AM17', null, null, 1, null, null, 'ALL',  MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID)
values ('SEARCHMENU', 'TPR', 10, 10, 'OPTION', 'SEARCHMORE', null, null, 1, null, null, 'ALL',  MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID)
values ('APPMENU', 'TPR', 15, 0, 'OPTION', 'VIEWCONT', null, null, 1, null, null, 'MAIN',  MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID)
values ('SEARCHMENU', 'TPR', 10, 30, 'OPTION', 'SEARCHTIPS', null, null, 1, null, null, 'ALL', MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID)
values ('APPMENU', 'TPR', 18, 0, 'HEADER', 'AM18', '附件库/文件夹', null, 1, null, null, 'ALL',  MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID)
values ('APPMENU', 'TPR', 18, 10, 'OPTION', 'MANAGELIB', null, null, 1, null, null, 'ALL',  MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID)
values ('APPMENU', 'TPR', 12, 0, 'OPTION', 'COMMCODE', null, null, 1, null, null, 'ALL', MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID)
values ('APPMENU', 'TPR', 11, 0, 'OPTION', 'CCODE', null, null, 1, null, null, 'MAIN', MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID)
values ('APPTOOL', 'TPR', 43, 0, 'OPTION', 'CREATEKPI', null, null, 1, 'nav_icon_kpi.gif', 'CTRL+ALT+K', 'LIST', MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID)
values ('SEARCHMENU', 'TPR', 20, 0, 'HEADER', 'SM20', '保存查询', null, 1, 'atb_save.gif', null, 'ALL',  MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID)
values ('SEARCHMENU', 'TPR', 20, 20, 'OPTION', 'SEARCHVMQR', null, null, 1, null, null, 'ALL',  MAXMENUSEQ.NEXTVAL);
commit; 

//通用菜单授权 (用于给用户组授权)
call PAK_TOOL.MenuPriv('TPR','MAXADMIN');

4    高级进阶
4.1    创建采购单
分析Maximo从采购申请创建采购单的功能,并将其进行扩展。下面描述整个过程:
4.1.1    创建菜单CREATEPO
在PR应用程序中添加CREATEPO(创建采购单)的菜单,并分配权限。
4.1.2    创建虚拟表PoFromPrInput
虚拟表主要用于弹出对话框中的信息填写。
 

4.1.3    编辑虚拟表的类
需要为虚拟表PoFromPrInput编写如下类:
?    PoFromPrInputRemote.java
?    PoFromPrInput.java
?    PoFromPrInputSetRemote.java
?    PoFromPrInputSet.java
以上类的编写与我们其它类的编写方法一样,再此不再叙述。
需要注意POFromPRInputSet.java的方法,如下图:
 

4.1.4    编辑PR.XML
 
说明:
字段    说明
Dialog的ID    此ID必须与sigoption.OptionName中的值、JavaBean中的函数名保持一致。
自动编号事件     setPOAutoKey一定要与POFromPRInput.java中的方法名保持一致。

4.1.5    编写JavaBean
编写JavaBean将通过菜单命令调用XML对话框。
PRAppBean.java代码片段如下:
 
    注:函数名CREATEPO一定要大写,且与XML对话框中的ID名字、数据库中的Sigoption.OptionName保持一致。
4.1.6    扩展自动编号按钮
扩展POFromPRInput.java为JxPOFromPRInput.java,重写SetPOAutoKey()方法,代码如下:
 
注意:方法名一定要与XML中的按钮事件名保持一致。

4.1.7    编写业务逻辑
业务逻辑类一般情况下如下:
?    PR.java
?    PRRemote.java
?    PRSet.java
?    PRSetRemote.java
以上的业务逻辑,就在JavaBean中调用即可。
4.2    将领料申请行项目复制到采购申请单
4.2.1    创建菜单COPYMRLNPR
在PR中创建菜单CopyMrlnPr,并分配权限,其SQL语句如下:

insert into sigoption (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD, ROWSTAMP)
values ('PR', 'COPYMRLNPR', '将领料申请行项目复制到采购申请单', 0, 1, '', '', 'READ', SIGOPTIONSEQ.Nextval, 'ZH', 0, maxseq.nextval);

insert into maxmenu (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID, ROWSTAMP)
values ('APPMENU', 'PR', 43, 0, 'OPTION', 'COPYMRLNPR', '', '', 1, '', '', 'MAIN', maxmenuseq.nextval, maxseq.nextval);

4.2.2    编辑PR.XML
编辑PR.XML,添加领料申请行列表对话框。
 
注:ID要与菜单保持同名。
4.2.3    扩展MRService
扩展MRService为JxMRService,参考如下:
 

4.2.4    扩展PR.JAVA
扩展PR.JAVA为JxPR.JAVA,添加复制领料申请行到采购申请行的功能。
copyMRLineToPRLine方法如下:
 
4.2.5    编写JavaBean
 
4.2.6    扩展PRLine.java
修改delete(long),undelete()方法,添加删除或取消删除时,更新MRLine。
Delete(long accessModifier)方法如下:

    file:///C|/Documents and Settings/Administrator/桌面/maximo60开发指南.txt(第 12/24 页)[2010-9-28 9:01:18]

----------------------- Page 13-----------------------

    file:///C|/Documents and Settings/Administrator/桌面/maximo60开发指南.txt

 
Undelete()方法如下:
 
------------------------------------------------------------------------------------------------
6    MAXIMO621开发流程
6.1    设计数库
设计人员根据需求分析,设计数据库,此环节开发人员不参与。
6.2    创建域
点击转到——配置——域,进入如下图所示域的操作页面。
 

 
注意:同义词域在页面无法添加,只能直接在数据库中添加。
6.2.1    创建状态同义词域的sql语句
1)在MAXDOMAIN表中添加记录:
insert into MAXDOMAIN (DOMAINID, DESCRIPTION, DOMAINTYPE, MAXTYPE, LENGTH, SCALE, MAXDOMAINID)
values ('STDSTATUS', '标准工作流状态', 'SYNONYM', 'UPPER', 10, 0, maxdomainseq.nextval);
2)在SYNONYMDOMAIN表中添加记录:
同义词域的每一个状态在SYNONYMDOMAIN表中对应一条记录。
insert into SYNONYMDOMAIN (DOMAINID, MAXVALUE, VALUE, DESCRIPTION, DEFAULTS, SITEID, ORGID, SYNONYMDOMAINID)
values ('STDSTATUS', 'APPR', 'APPR', '已批准', 1, null, null, synonymdomainseq.nextval);
insert into SYNONYMDOMAIN (DOMAINID, MAXVALUE, VALUE, DESCRIPTION, DEFAULTS, SITEID, ORGID, SYNONYMDOMAINID)
values ('STDSTATUS', 'CAN', 'CAN', '已取消', 1, null, null, synonymdomainseq.nextval);
insert into SYNONYMDOMAIN (DOMAINID, MAXVALUE, VALUE, DESCRIPTION, DEFAULTS, SITEID, ORGID, SYNONYMDOMAINID)
values ('STDSTATUS', 'CLOSE', 'CLOSE', '关闭', 1, null, null, synonymdomainseq.nextval);
insert into SYNONYMDOMAIN (DOMAINID, MAXVALUE, VALUE, DESCRIPTION, DEFAULTS, SITEID, ORGID, SYNONYMDOMAINID)
values ('STDSTATUS', 'WAPPR', 'WAPPR', '等待批准', 1, null, null, synonymdomainseq.nextval);
insert into SYNONYMDOMAIN (DOMAINID, MAXVALUE, VALUE, DESCRIPTION, DEFAULTS, SITEID, ORGID, SYNONYMDOMAINID)
values ('STDSTATUS', 'INPRG', 'INPRG', '进行中', 1, null, null, synonymdomainseq.nextval);

同义词域对应工作流中对象的状态;
创建后使用存储过程为主对象的STATUS字段配置域:
call PAK_TOOL.ConfigDomain('TPR','STATUS','STDSTATUS');
6.3    新建模块和服务
模块指的是点击“转到”弹出的下拉列表中的各个应用模块。
Maximo没有提供创建模块的页面,必须在数据库中利用sql语句在MAXMODULES表中添加。
添加模块后还必须MAXMENU中添加菜单。
例如:
insert into MAXMODULES (MODULE, DESCRIPTION, MAXMODULESID)
values ('TR', '技改', maxmodulesseq.nextval);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID)
values ('MODULE', 'TR', 4000, 0, 'MODULE', 'TR', null, null, 1, null, null, null, maxmenuseq.nextval);
commit;

 

Maximo也没有提供创建服务的页面,必须在数据库中利用sql语句在MAXSERVICE表中添加。
注意:服务名、绑定的类名及路径是一一对应的,建议新建的主对象最好都创建自己单独的服务,服务名跟主对象名一样,这样方便每个应用的业务逻辑代码都发布在自己的服务目录下,不是主对象的对象引用现有的服务名,而不重新创建服务。
开发出服务类后在maximo数据库的MAXSERVICE表中配置相应服务,可以使用如下的sql语句:
insert into MAXSERVICE
(servicename,description,classname,maxserviceid) values
('TPRSERVICE','工程项目申请,'com.jxkj.app.tpr.TprService',maxserviceseq.nextval);
或者使用存储过程:
call PAK_TOOL.CofigServiceName('TPR','工程项目申请','com.jxkj.app.tpr.TprService');

6.4    创建数据库表
开发人员通过 ‘转到→配置→数据库配置’创建数据库。如下所示界面:
 
创建数据库表需注意的问题:
1.    是否主对象(有工流需要钩上)、服务名、表所属级别、主列等。
2.    在界面上创建好对象还没执行cofigdb之前,maximo会往maxtablecfg、maxobjectcfg、maxattributecfg这些表插入记录,还没生成往oracle生成相应的物理表,执行完configdb后,会在数据库中生成相应的物理表,并往maxtable、maxobject、maxattribute这些maximo系统表插入记录,如果configdb时出现问题,可以查看这些maximo系统表
3.    创建虚拟的状态表时,级别为SYSTEM,固定和添加Rowstamp不用√,唯一列跟语言列都不用添,因为虚拟表在数据库中不存在相应的物理表,设计界面如下
 
6.5    通过CONFIGDB配置数据库
创建完数据库表关闭weblogic,等待大概1分钟,转到\maximo\tools\maximo目录中,执行configdb.bat命令,命令的默认参数将以,\Maximo\applications\maximo\properties\maximo.properties中的参数为准。

6.6    创建应用
开发人员通过 ‘转到→配置→应用程序设计器’创建应用,在无特别说明的前提下,默认创建为高级应用程序。设计界面如下:
 
6.7    设计应用程序界面
开发人员有两和方式设计应用程序:
1.    ‘转到→配置→应用程序设计器’设计界面(初学者大都使用此种方式)。
如下图所示:
 
2.    直接编辑XML文件,设计界面。
设计界面需注意的问题:
1.    
2.    

6.8    添加应用程序通用菜单和签名选项
有两种方式创建应用程序菜单和签名选项:
1.    在‘转到→配置→应用程序设计器→选择操作’中可以进行添加/修改签名选项、添加/修改选择操作菜单、添加/修改工具栏菜单、添加/修改搜索菜单
2.    直接通过sql语句,如下所示创建
--应用程序消息
insert into Maxmessages (msgkey,msggroup,value,title,displaymethod,options,buttontext,maxmessagesid) Values ('StatusChangeSuccess','receiption','接待方案 {0} 状态被更改为 {1}。',null,'STATUS',2,null,MaxmessagesSEQ.nextval);
insert into  Maxmessages (msgkey,msggroup,value,title,displaymethod,options,buttontext,maxmessagesid) Values ('StatusChangeFailure','receiption','无法将采购申请 {0} 状态更改为 {1}。',null,'MSGBOX',2,null,MaxmessagesSEQ.nextval);
insert into  Maxmessages (msgkey,msggroup,value,title,displaymethod,options,buttontext,maxmessagesid) Values ('editHistErr','receiption','仅当处于“关闭”状态时,才能执行“编辑历史”操作。。',null,'MSGBOX',2,null,MaxmessagesSEQ.nextval);
insert into  Maxmessages (msgkey,msggroup,value,title,displaymethod,options,buttontext,maxmessagesid) Values ('cannotdeletereceiption','receiption','状态改变后不能删除',null,'MSGBOX',2,null,MaxmessagesSEQ.nextval);
insert into  Maxmessages (msgkey,msggroup,value,title,displaymethod,options,buttontext,maxmessagesid) Values ('cannotdeleteline','receiption','如果处于“等待批准”状态,则只能删除行',null,'MSGBOX',2,null,MaxmessagesSEQ.nextval);
--创建签名选项
insert into SIGOPTION (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD) values ('RECEIPTION','BOOKMARK','添加到书签','0','0','','','READ',SIGOPTIONSEQ.NEXTVAL,'ZH','0');
insert into SIGOPTION (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD) values ('RECEIPTION','INSERT','新建接待方案记录','0','1','SAVE','DUPLICATE','READ',SIGOPTIONSEQ.NEXTVAL,'ZH','0');
insert into SIGOPTION (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD) values ('RECEIPTION','NEXT','下一个接待方案','0','1','','','READ',SIGOPTIONSEQ.NEXTVAL,'ZH','0');
insert into SIGOPTION (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD) values ('RECEIPTION','PREVIOUS','上一个接待方案','0','1','','','READ',SIGOPTIONSEQ.NEXTVAL,'ZH','0');
insert into SIGOPTION (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD) values ('RECEIPTION','SAVE','保存记录','0','1','','INSERT, DUPLICATE, FIELDDEFS','READ',SIGOPTIONSEQ.NEXTVAL,'ZH','0');
insert into SIGOPTION (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD) values ('RECEIPTION','CLEAR','清除更改','0','1','','','READ',SIGOPTIONSEQ.NEXTVAL,'ZH','0');
insert into SIGOPTION (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD) values ('RECEIPTION','RUNREPORTS','运行报表','0','1','','','READ',SIGOPTIONSEQ.NEXTVAL,'ZH','0');
--insert into SIGOPTION (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD) values ('RECEIPTION','READ','读取接待流程','0','1','CLEAR, NEXT, PREVIOUS, BOOKMARK, VIEWHIST','ALL','',SIGOPTIONSEQ.NEXTVAL,'ZH','0');
insert into SIGOPTION (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD) values ('RECEIPTION','SEARCHMORE','更多搜索字段','0','1','','','READ',SIGOPTIONSEQ.NEXTVAL,'ZH','0');
insert into SIGOPTION (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD) values ('RECEIPTION','SEARCHTIPS','查看搜索提示','0','1','','','READ',SIGOPTIONSEQ.NEXTVAL,'ZH','0');
insert into SIGOPTION (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD) values ('RECEIPTION','SEARCHWHER','Where 子句','0','1','','','READ',SIGOPTIONSEQ.NEXTVAL,'ZH','0');
insert into SIGOPTION (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD) values ('RECEIPTION','CREATEKPI','创建 KPI','0','1','','','READ',SIGOPTIONSEQ.NEXTVAL,'ZH','0');
insert into SIGOPTION (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD) values ('RECEIPTION','SEARCHBOOK','书签','0','1','','','READ',SIGOPTIONSEQ.NEXTVAL,'ZH','0');
insert into SIGOPTION (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD) values ('RECEIPTION','SEARCHSQRY','保存当前查询','0','1','','','READ',SIGOPTIONSEQ.NEXTVAL,'ZH','0');
insert into SIGOPTION (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD) values ('RECEIPTION','SEARCHVMQR','查看/管理查询','0','1','','','READ',SIGOPTIONSEQ.NEXTVAL,'ZH','0');
insert into SIGOPTION (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD) values ('RECEIPTION','MANAGELIB','管理库','0','1','','','READ',SIGOPTIONSEQ.NEXTVAL,'ZH','0');
insert into SIGOPTION (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD) values ('RECEIPTION','MANAGEFOLD','管理文件夹','0','1','','','READ',SIGOPTIONSEQ.NEXTVAL,'ZH','0');
insert into SIGOPTION (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD) values ('RECEIPTION','ASSOCFOLD','相关文件夹','0','1','','','READ',SIGOPTIONSEQ.NEXTVAL,'ZH','0');
insert into SIGOPTION (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD) values ('RECEIPTION','EDITHIST','编辑历史记录','0','1','','','READ',SIGOPTIONSEQ.NEXTVAL,'ZH','0');
insert into SIGOPTION (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD) values ('RECEIPTION','DELETE','删除记录','0','1','','','READ',SIGOPTIONSEQ.NEXTVAL,'ZH','0');
insert into SIGOPTION (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD) values ('RECEIPTION','DUPLICATE','复制接待方案','0','1','','','INSERT',SIGOPTIONSEQ.NEXTVAL,'ZH','0');
insert into SIGOPTION (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD) values ('RECEIPTION','ASSIGNWF','查看工作流任务分配','0','1','','','',SIGOPTIONSEQ.NEXTVAL,'ZH','0');
insert into SIGOPTION (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD) values ('RECEIPTION','HELPWF','工作流帮助','0','1','','','',SIGOPTIONSEQ.NEXTVAL,'ZH','0');

    file:///C|/Documents and Settings/Administrator/桌面/maximo60开发指南.txt(第 13/24 页)[2010-9-28 9:01:18]

----------------------- Page 14-----------------------

    file:///C|/Documents and Settings/Administrator/桌面/maximo60开发指南.txt

insert into SIGOPTION (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD) values ('RECEIPTION','HISTORYWF','查看工作流历史','0','1','','','',SIGOPTIONSEQ.NEXTVAL,'ZH','0');
insert into SIGOPTION (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD) values ('RECEIPTION','ROUTEWF','发送工作流','0','1','','','',SIGOPTIONSEQ.NEXTVAL,'ZH','0');
insert into SIGOPTION (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD) values ('RECEIPTION','STOPWF','停止工作流','0','1','','','',SIGOPTIONSEQ.NEXTVAL,'ZH','0');
insert into SIGOPTION (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD) values ('RECEIPTION','VIEWWF','查看工作流地图','0','1','','','',SIGOPTIONSEQ.NEXTVAL,'ZH','0');
insert into SIGOPTION (APP, OPTIONNAME, DESCRIPTION, ESIGENABLED, VISIBLE, ALSOGRANTS, ALSOREVOKES, PREREQUISITE, SIGOPTIONID, LANGCODE, HASLD) values ('RECEIPTION','STATUS','更改状态','0','1','','','SAVE',SIGOPTIONSEQ.NEXTVAL,'ZH','0');

--创建应用程序菜单
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID) values ('APPMENU','RECEIPTION','85','0','HEADER','AM85','附件库/文件夹','','1','','','ALL',MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID) values ('APPMENU','RECEIPTION','85','10','OPTION','MANAGELIB','','','1','','','ALL',MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID) values ('APPMENU','RECEIPTION','85','20','OPTION','MANAGEFOLD','','','1','','','ALL',MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID) values ('APPMENU','RECEIPTION','85','30','OPTION','ASSOCFOLD','','','1','','','ALL',MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID) values ('APPMENU','RECEIPTION','80','0','SEP','AM80','','','1','','','MAIN',MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID) values ('SEARCHMENU','RECEIPTION','10','30','OPTION','SEARCHTIPS','','','1','','','ALL',MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID) values ('APPTOOL','RECEIPTION','93','0','OPTION','CREATEKPI','','','1','nav_icon_kpi.gif','CTRL+ALT+K','LIST',MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID) values ('SEARCHMENU','RECEIPTION','20','20','OPTION','SEARCHVMQR','','','1','','','ALL',MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID) values ('SEARCHMENU','RECEIPTION','20','10','OPTION','SEARCHSQRY','','','1','','','ALL',MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID) values ('SEARCHMENU','RECEIPTION','10','0','HEADER','SM10','高级搜索','','1','atb_search.gif','','ALL',MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID) values ('SEARCHMENU','RECEIPTION','10','20','OPTION','SEARCHWHER','','','1','','','ALL',MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID) values ('SEARCHMENU','RECEIPTION','30','0','OPTION','SEARCHBOOK','','','1','atb_bookmark.gif','','ALL',MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID) values ('SEARCHMENU','RECEIPTION','20','0','HEADER','SM20','保存查询','','1','atb_save.gif','','ALL',MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID) values ('APPMENU','RECEIPTION','40','0','SEP','AM40','','','1','','','',MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID) values ('APPTOOL','RECEIPTION','40','0','SEP','AT40','','','1','','','',MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID) values ('APPMENU','RECEIPTION','41','0','OPTION','DUPLICATE','','','1','','','MAIN',MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID) values ('APPMENU','RECEIPTION','42','0','OPTION','EDITHIST','','','1','','','MAIN',MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID) values ('APPMENU','RECEIPTION','43','0','OPTION','DELETE','','','1','','','MAIN',MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID) values ('APPTOOL','RECEIPTION','12','0','OPTION','INSERT','','','1','nav_icon_insertkey.gif','CTRL+ALT+I','ALL',MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID) values ('APPTOOL','RECEIPTION','23','0','OPTION','NEXT','','','1','nav_icon_next.gif','CTRL+ALT+N','MAIN',MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID) values ('APPTOOL','RECEIPTION','22','0','OPTION','PREVIOUS','','','1','nav_icon_previous.gif','CTRL+ALT+P','MAIN',MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID) values ('APPTOOL','RECEIPTION','13','0','OPTION','SAVE','','','1','nav_icon_save.gif','CTRL+ALT+S','MAIN',MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID) values ('APPTOOL','RECEIPTION','14','0','OPTION','CLEAR','','','1','nav_icon_clear.gif','CTRL+ALT+C','MAIN',MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID) values ('APPMENU','RECEIPTION','9001','0','OPTION','RUNREPORTS','','','1','','','ALL',MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID) values ('APPMENU','RECEIPTION','92','0','OPTION','BOOKMARK','','','1','','','MAIN',MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID) values ('APPMENU','RECEIPTION','70','0','SEP','AM70','','','1','','','',MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID) values ('APPMENU','RECEIPTION','90','0','SEP','AM90','','','1','','','',MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID) values ('APPTOOL','RECEIPTION','30','0','SEP','AT30','','','1','','','',MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID) values ('APPMENU','RECEIPTION','72','0','OPTION','SCHARGES','','','1','','','MAIN',MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID) values ('SEARCHMENU','RECEIPTION','10','10','OPTION','SEARCHMORE','','','1','','','ALL',MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID) values ('APPMENU','RECEIPTION','9000','0','SEP','AM9000','','','1','','','',MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID) values ('APPTOOL','RECEIPTION','20','0','SEP','AT20','','','1','','','',MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID) values ('APPMENU','RECEIPTION','10','60','OPTION','HELPWF','','','1','','','MAIN',MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID) values ('APPMENU','RECEIPTION','10','50','OPTION','VIEWWF','','','1','','','MAIN',MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID) values ('APPMENU','RECEIPTION','10','40','OPTION','ASSIGNWF','','','1','','','MAIN',MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID) values ('APPMENU','RECEIPTION','10','30','OPTION','HISTORYWF','','','1','','','MAIN',MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID) values ('APPMENU','RECEIPTION','10','20','OPTION','STOPWF','','','1','','','MAIN',MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID) values ('APPMENU','RECEIPTION','10','10','OPTION','ROUTEWF','','','1','','','MAIN',MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID) values ('APPMENU','RECEIPTION','10','0','HEADER','','工作流','','1','','','MAIN',    MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID) values ('APPMENU','RECEIPTION','31','0','OPTION','STATUS','','','1','nav_icon_changestatus.gif','CTRL+ALT+A','ALL',    MAXMENUSEQ.NEXTVAL);
insert into MAXMENU (MENUTYPE, MODULEAPP, POSITION, SUBPOSITION, ELEMENTTYPE, KEYVALUE, HEADERDESCRIPTION, URL, VISIBLE, IMAGE, ACCESSKEY, TABDISPLAY, MAXMENUID) values ('APPTOOL','RECEIPTION','32','0','OPTION','STATUS','','','1','nav_icon_changestatus.gif','CTRL+ALT+A','ALL',    MAXMENUSEQ.NEXTVAL);
6.9    分配权限
  ‘转到→权限组→查找并点击“MAXADMIN”组→应用程序→查找到相应的应用程序并为该权限组赋予相应的权限,一般是所有都打上钩,即赋予所有权限。配置完权限,退出maximo重新登录即可。
6.10    编写业务罗辑类
设计好应用后,需要编写应用用到的业务逻辑类,一般有:服务类、Mbo类、Set集合类、字段验证类,如果有工作流,则还需要编写状态表的Mbo类和Set集合类、StatusHandler类、虚拟表的Mbo类和Set集合类。
6.10.1    开发服务类
?    定义
Maximo把功能类似的一系列的应用归为一个服务,并由统一的类来管理。一个应用程序的所有对象都对应同一个服务。
?    程序实现
1.    创建服务接口
服务接口必须继承psdi.server.AppServiceRemote接口;
2.    创建服务类
服务类必须继承psdi.server.AppService,同时实现创建的服务接口;并且定义如TprService(MXServer mxServer)的带参的构造函数。注意:目前service类中还不写逻辑,只继承超类,由超类来完成其全部实现。创建服务类的目的是方便程序的扩展。
6.10.2     开发MboSet类
?    定义
MboSet是Maximo中持久层的核心类,其核心的超类psdi.mbo.MboSet。
应用程序对象与MboSet类直接关联,在创建对象时必须指定与对象关联的MboSet类。MboSet类主要用来返回Mbo类的实例。
?    程序实现
MboSet类必须继承psdi.mbo.MboSet类,实现psdi.mbo.MboSetRemote接口;
1)    必须定义如TprMboSet(MboServerInterface arg0)的构造方法;实现getMboInstance(MboSet arg0)方法,在该方法中返回Mbo类的实例。
6.10.3    开发Mbo类
?    定义
Mbo是Maximo中持久层的核心类,用来处理与数据库的所有操作。其核心的超类是psdi.mbo.Mbo。Mbo类又分为有状态的Mbo和无状态的Mbo。无状态的Mbo的例子为psdi.mbo.custapp.CustomMbo和psdi.mbo.custapp.CustomMboSet,不考虑应用中状态的变化,所有新建的对象都会使用这个Mbo。而一个有状态的Mbo,如工单,是会发生自己的变化的,系统中没有提供新建一个有状态的Mbo的功能,目前必须自定义。

?    程序实现
以下介绍有状态Mbo类的实现。
有状态Mbo类必须继承psdi.mbo.StatefulMbo类,实现psdi.mbo.StatefulMboRemote接口。
1)    必须定义如TprMbo(MboSet arg0)的构造方法;
2)    实现getStatusHandler()方法,在该方法中返回自定义StatusHandler类的实例;
3)    实现getStatusHistory()方法,在该方法中返回主对象与关系对象的关系名称;
4)    实现getStatusListName()方法,在该方法中返回一个定义好的状态synonym域的名称。如:WOSTATUS;
6.10.4    开发StatusHandler类
?    定义
该类用于工作流中更改状态。

?    程序实现
StatusHandler必须继承psdi.mbo.StatusHandler类。
1)必须定义如TprStatusHandler(StatefulMbo sm)的构造方法
并覆写如下两个方法:checkStatusChangeAuthorization(String s),
changeStatus(String s, String s1, Date date, String s2):用来做状态的改变。
各种类的方法说明及例子参见附录 
6.11    编译业务逻辑类
编写完业务逻辑类,编写一个bat脚本文件来把业务逻辑类的class文件发布到..\maximo\businessobjects.jar目录下。该bat脚本必须包含应用所用到的Mbo类、Service服务类、Set集合类。如下所示:

@echo off
set MAX_HOME=..\..\maximo
set JXCLASS_HOME=..\classes
set cpath=..\lib\businessobjects.jar;..\lib\log4j-1.2.8.jar;.;%JXCLASS_HOME%
set App=receiption
set java_bin=%JAVA_HOME%\bin

@echo.
@echo classpath=%cpath%
@echo max_home=%MAX_HOME%
@echo %java_bin%
@echo.

if "%1"=="/n" goto COPY
if "%1"=="/copy" goto COPY

%java_bin%\rmic -v1.2 -classpath %cpath% -d %JXCLASS_HOME%\ com.jxkj.app.%App%.ReceiptionService
%java_bin%\rmic -v1.2 -classpath %cpath% -d %JXCLASS_HOME%\ com.jxkj.app.%App%.Receiption
%java_bin%\rmic -v1.2 -classpath %cpath% -d %JXCLASS_HOME%\ com.jxkj.app.%App%.ReceiptionSet
%java_bin%\rmic -v1.2 -classpath %cpath% -d %JXCLASS_HOME%\ com.jxkj.app.%App%.ReceiptionGuest
%java_bin%\rmic -v1.2 -classpath %cpath% -d %JXCLASS_HOME%\ com.jxkj.app.%App%.ReceiptionGuestSet
%java_bin%\rmic -v1.2 -classpath %cpath% -d %JXCLASS_HOME%\ com.jxkj.app.%App%.ReceiptionStatus

    file:///C|/Documents and Settings/Administrator/桌面/maximo60开发指南.txt(第 14/24 页)[2010-9-28 9:01:18]

----------------------- Page 15-----------------------

     file:///C|/Documents and Settings/Administrator/桌面/maximo60开发指南.txt

%java_bin%\rmic -v1.2 -classpath %cpath% -d %JXCLASS_HOME%\ com.jxkj.app.%App%.ReceiptionStatusSet
%java_bin%\rmic -v1.2 -classpath %cpath% -d %JXCLASS_HOME%\ com.jxkj.app.%App%.virtual.CReceiptionStatus
%java_bin%\rmic -v1.2 -classpath %cpath% -d %JXCLASS_HOME%\ com.jxkj.app.%App%.virtual.CReceiptionStatusSet

@echo on
:COPY

@xcopy /s /y %JXCLASS_HOME%\com\jxkj\app\%App%\*.* %MAX_HOME%\businessobjects.jar\com\jxkj\app\%App%\
@xcopy /s /y %JXCLASS_HOME%\com\jxkj\webclient\beans\%App%\*.* %MAX_HOME%\maximouiweb.war\WEB-INF\classes\com\jxkj\webclient\beans\%App%\
@goto END

:END
@echo %time%

@pause
重启weblogic,重新登录maximo即可

6.12    画工作流图
登录到maximo后,点击转到→配置→工作流→工作流设计器,点击 新建工作流,出现工作流设计界面,如下图所示:
 
可以在设计界面上进行设计,其中需要注意的问题有:
1.    用户的创建。创建用户时需要把它分配到某个权限组中,也可以在某个权限组中添加该用户
2.    工作流画完后,启动顺序为:验证过程→启用过程→激活过程→添加工作流到应用程序→“编辑工作流至”按钮
3.    要修改工作流图时,禁用顺序为:使过程无效→禁用过程
4.    “编辑工作流至”按钮时,如果出现违反唯一性错误则执行一下sql语句:
select nextval from dual
并把序号值取为nextval+1

6.13    应用程序单元测试
7    附录
7.1    业务逻辑类方法说明
7.1.1    服务类
1.    服务接口
注意:服务接口必须继承psdi.server.AppServiceRemote接口
示例:

package com.jxkj.app.tpr;

import psdi.server.AppServiceRemote;

public interface ITprService extends AppServiceRemote
{
//根据业务逻辑,可以在这里添加新的方法以扩展AppServiceRemote接口
}
服务类
2.    服务类
注意:服务类必须继承psdi.server.AppService,同时实现创建的服务接口;并且定义如TprService(MXServer mxServer)的带参的构造函数。目前service类中还不写逻辑,只继承超类,由超类来完成其全部实现。创建服务类的目的是方便程序的扩展
示例:

package com.jxkj.app.tpr;

import java.rmi.RemoteException;

import psdi.server.AppService;
import psdi.server.MXServer;

public class TprService extends AppService implements ITprService
{
    public TprService() throws RemoteException
    {
    super();
    }
//必须定义以下构造函数
    public TprService(MXServer mxServer) throws RemoteException
    {//
    super(mxServer);
    }

}

7.1.2    MboSet类
注意:MboSet类必须继承psdi.mbo.MboSet类,实现psdi.mbo.MboSetRemote接口;
由于应用程序对象与MboSet类直接关联,在创建对象时必须指定与对象关联的MboSet类。MboSet类主要用来返回Mbo类的实例,因此必须定义如TprMboSet(MboServerInterface arg0)的构造方法;实现getMboInstance(MboSet arg0)方法,在该方法中返回Mbo类的实例,切记要返回并且要返回正确的Mbo类的实例。
1.    主对象MboSet
package com.jxkj.app.tpr;

import java.rmi.RemoteException;

import psdi.mbo.Mbo;
import psdi.mbo.MboServerInterface;
import psdi.mbo.MboSet;
import psdi.mbo.MboSetRemote;
import psdi.util.MXException;

public class TprMboSet extends MboSet implements MboSetRemote
{

    public TprMboSet(MboServerInterface mboserverinterface) throws MXException, RemoteException
    {
    super(mboserverinterface);
    }

    protected Mbo getMboInstance(MboSet ms) throws MXException, RemoteException
    {//必须返回正确的Mbo类实例
    return new TprMbo(ms);
    }

}

2.    状态对象的MboSet跟其他对象一样

package com.jxkj.app.tpr;

import java.rmi.RemoteException;

import psdi.mbo.Mbo;
import psdi.mbo.MboServerInterface;
import psdi.mbo.MboSet;
import psdi.mbo.MboSetRemote;
import psdi.util.MXException;

     file:///C|/Documents and Settings/Administrator/桌面/maximo60开发指南.txt(第 15/24 页)[2010-9-28 9:01:18]

----------------------- Page 16-----------------------

     file:///C|/Documents and Settings/Administrator/桌面/maximo60开发指南.txt

public class TprStatusMboSet extends MboSet implements MboSetRemote
{
    public TprStatusMboSet(MboServerInterface ms) throws RemoteException
    {
    super(ms);
    }

    protected Mbo getMboInstance(MboSet ms) throws MXException, RemoteException
    {//必须返回正确的Mbo类实例
    return new TprStatusMbo(ms);
    }

}

3.    虚拟表对象的MboSet
稍有不同,它必须继承psdi.app.common.virtual.ChangeStatusSet,并实现psdi.mbo.NonPersistentMboSetRemote接口
package com.jxkj.app.tpr.virtual;

import java.rmi.RemoteException;

import psdi.app.common.virtual.ChangeStatusSet;
import psdi.mbo.Mbo;
import psdi.mbo.MboRemote;
import psdi.mbo.MboServerInterface;
import psdi.mbo.MboSet;
import psdi.mbo.MboSetRemote;
import psdi.mbo.NonPersistentMboSetRemote;
import psdi.mbo.SqlFormat;
import psdi.util.MXException;

import com.jxkj.app.tpr.TprMbo;

public class CTprStatusMboSet extends ChangeStatusSet implements NonPersistentMboSetRemote
{

    public CTprStatusMboSet (MboServerInterface ms) throws MXException, RemoteException
    {
    super(ms);
    }
    
    // 返回Mbo实例,就是虚拟表对象的Mbo实例
    protected Mbo getMboInstance(MboSet ms) throws MXException, RemoteException
    {
    return new CTprStatusMbo(ms);
    }

    protected MboSetRemote getMboIntoSet(MboRemote mbo) throws MXException, RemoteException
    {
    // 通过where子句返回主对象Mbo
    MboSetRemote changeWOSet = getMboServer().getMboSet("TPR", getUserInfo());
    SqlFormat sqf = new SqlFormat(mbo, "tprnum = :tprnum and siteid = :siteid");
    changeWOSet.setWhere(sqf.format());
    return changeWOSet;
    }

    protected void changeMboStatus(MboRemote tpr, MboRemote param) throws MXException, RemoteException
{
//调用主对象的changeStatus方法来改变主对象的状态
    ((TprMbo) tpr).changeStatus(param.getString("status"), param.getDate("statdate"), param.getString("memo"));
    }

7.1.3    Mbo类
1.    无状态的Mbo类
无状态的Mbo类必须继承psdi.mbo.Mbo,实现psdi.mbo.MboRemote接口,以后开发,非工作流表可以继承com.jxkj.mbo. JxMbo(继承psdi.mbo.Mbo),实现com.jxkj.mbo. JxMboRemote(继承psdi.mbo.MboRemote)接口
1)    主对象的Mbo
示例:

package com.jxkj.app.htr;

import java.rmi.RemoteException;
import java.util.HashSet;

import org.apache.log4j.Logger;

import psdi.app.person.Person;
import psdi.mbo.MboRemote;
import psdi.mbo.MboSet;
import psdi.mbo.MboSetRemote;
import psdi.mbo.MboValueInfo;
import psdi.server.MXServer;
import psdi.util.MXAccessException;
import psdi.util.MXApplicationWarningException;
import psdi.util.MXException;

import com.jxkj.mbo.JxMbo;

public class HTR extends JxMbo implements HTRRemote {
    private Logger logger = Logger.getLogger(HTR.class);

    private static HashSet skipFieldCopy = new HashSet();

    private static boolean isHashSetLoaded = false;

    boolean isModified;
    
    public HTR(MboSet mboSet) throws RemoteException {
        super(mboSet);
        isModified=false;
        // TODO Auto-generated constructor stub
    }
    public void init() throws MXException {
        super.init();
        if (!toBeAdded()) {
            try {
                setFlag(READONLY, getBoolean("historyflag"));
                if(getMboValue("PERSONID")==null)
                    throw new MXApplicationWarningException("htr", "personid");
            } catch (RemoteException ex) {
                logger.debug(ex.getMessage());
            }

     file:///C|/Documents and Settings/Administrator/桌面/maximo60开发指南.txt(第 16/24 页)[2010-9-28 9:01:18]

----------------------- Page 17-----------------------

      file:///C|/Documents and Settings/Administrator/桌面/maximo60开发指南.txt

        }
    }
/*新增一条记录时调用add方法
*一般是用来为某些不需用户输入的字段赋值
*
*/
    public void add() throws RemoteException, MXException {
        super.add();
        setValue("HISTORYFLAG", false, NOACCESSCHECK | NOVALIDATION_AND_NOACTION);
        setValue("RTIME", MXServer.getMXServer().getDate(), NOACCESSCHECK | NOVALIDATION_AND_NOACTION);
    }
/*修改记录时调用modify方法
*如果有修改則更新changeby和changedate字段值
*
*/

    public void modify() throws RemoteException, MXException {
        if (!isModified) {
            isModified = true;
            setValue("CHANGEBY", getUserInfo().getPersonId(), NOACCESSCHECK | NOVALIDATION_AND_NOACTION);
        }
        setValue("CHANGEDATE", MXServer.getMXServer().getDate(), NOACCESSCHECK | NOVALIDATION_AND_NOACTION);
    }
    
    public void generateAutoKey() throws RemoteException, MXException {
        if (toBeAdded()) {
            getMboValue("HTRNUM").autoKey();
        } else {
            Object param[] = { getName() };
            throw new MXAccessException("access", "CantGenAutoKey", param);
        }
    }
/*复制记录时调用duplicate方法
*
*复制记录时也要复制附属记录
*/

    public MboRemote duplicate() throws MXException, RemoteException {
        if (!isHashSetLoaded)
            loadSkipFieldCopyHashSet();
        MboRemote newMbo = copy();
        MboSetRemote myDoclinksSetRemote = getMboSet("DOCLINKS");
        if (!myDoclinksSetRemote.isEmpty())
            myDoclinksSetRemote.copy(newMbo.getMboSet("DOCLINKS"));
        MboSetRemote myPersonSetRemote = getMboSet("PERSONID");
        if (!myPersonSetRemote.isEmpty())
            myPersonSetRemote.copy(newMbo.getMboSet("PERSONID"));
        MboSetRemote myHTRLineSetRemote = getMboSet("HTRLINE");
        if (!myHTRLineSetRemote.isEmpty())
            myHTRLineSetRemote.copy(newMbo.getMboSet("HTRLINE"));
        return newMbo;
    }

    private static void loadSkipFieldCopyHashSet() throws MXException, RemoteException {
        isHashSetLoaded = true;
        skipFieldCopy.add("HTRNUM");
        skipFieldCopy.add("CHANGEDATE");
        skipFieldCopy.add("CHANGEBY");
        skipFieldCopy.add("ORGID");
        skipFieldCopy.add("SITEID");
    }
    
    protected boolean skipCopyField(MboValueInfo mvi) throws RemoteException, MXException {
        return skipFieldCopy.contains(mvi.getName());
    }
    /**
     * 归档和反归档
     * @throws RemoteException
     * @throws MXException
     */
    public void archive() throws RemoteException, MXException
    {
        setValue("historyflag", !getBoolean("historyflag"), NOACCESSCHECK
                | NOVALIDATION_AND_NOACTION);
    }
    /**
     * 删除附属记录
     */
    public void delete(long accessModifier) throws RemoteException, MXException {
        getMboSet("HTRLINE").deleteAll();
        super.delete(accessModifier);
    }
    
}

2)    子对象的Mbo类

package com.jxkj.app.htr;

import java.rmi.RemoteException;
import java.util.HashSet;

import org.apache.log4j.Logger;

import psdi.mbo.MboRemote;
import psdi.mbo.MboSet;
import psdi.mbo.MboSetRemote;
import psdi.mbo.MboValueInfo;
import psdi.util.MXException;
import com.jxkj.mbo.JxMbo;

public class HTRLine extends JxMbo implements HTRLineRemote {
    private Logger logger = Logger.getLogger(HTRLine.class);

    static HashSet fieldsNeedFlags = null;

    private static HashSet skipFieldCopy = new HashSet();

    private static boolean isHashSetLoaded = false;

    boolean fromVendorItem;
    

      file:///C|/Documents and Settings/Administrator/桌面/maximo60开发指南.txt(第 17/24 页)[2010-9-28 9:01:18]

----------------------- Page 18-----------------------

      file:///C|/Documents and Settings/Administrator/桌面/maximo60开发指南.txt

    public HTRLine(MboSet mboSet) throws RemoteException {
        super(mboSet);
        // TODO Auto-generated constructor stub
    }
    public void init() throws MXException {
        super.init();
        HTRRemote owner = (HTRRemote) getOwner();
        try {
            boolean historyflag = owner.getBoolean("historyflag");
            if (historyflag) {
                setFlag(READONLY, owner.getBoolean("historyflag"));
            }
        } catch (RemoteException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public void add() throws MXException, RemoteException {
        super.add();
        HTRRemote owner = (HTRRemote) getOwner();
        setValue("HTRNUM", owner.getString("HTRNUM"), 11L);
    }

    protected boolean skipCopyField(MboValueInfo mvi) throws RemoteException, MXException {
        if (!isHashSetLoaded)
            loadSkipFieldCopyHashSet();
        return skipFieldCopy.contains(mvi.getName());
    }

    private static void loadSkipFieldCopyHashSet() throws MXException, RemoteException {
        isHashSetLoaded = true;
        skipFieldCopy.add("HTRNUM");
        skipFieldCopy.add("ORGID");
        skipFieldCopy.add("SITEID");
    }

    public MboRemote duplicate() throws MXException, RemoteException {
        if (!isHashSetLoaded)
            loadSkipFieldCopyHashSet();
        MboRemote newMbo = copy();
        MboSetRemote myDoclinksSetRemote = getMboSet("DOCLINKS");
        if (!myDoclinksSetRemote.isEmpty())
            myDoclinksSetRemote.copy(newMbo.getMboSet("DOCLINKS"));
        MboSetRemote myCompanySetRemote = getMboSet("COMPANY");
        if (!myCompanySetRemote.isEmpty())
            myCompanySetRemote.copy(newMbo.getMboSet("COMPANY"));

        return newMbo;
    }

    public void propagateKeyValue(String keyName, String keyValue) throws MXException, RemoteException {
        if (keyName.equalsIgnoreCase("HTRNUM"))
            setValue("HTRNUM", keyValue, 11L);
        MboSetRemote prCosts = getMboSet("HTRLINE");
        MboRemote prCost = null;
        for (prCost = prCosts.moveFirst(); prCost != null; prCost = prCosts.moveNext())
            prCost.setValue("HTRNUM", keyValue, 11L);
    }
    
}

2.    有状态的Mbo类
1)    主对象的Mbo类
有状态的Mbo类必须继承psdi.mbo.StatefulMbo,实现psdi.mbo.MboRemote接口,以后开发,工作流表可以继承com.jxkj.mbo.JxStatefulMbo(继承psdi.mbo.Mbo),实现com.jxkj.mbo. JxMboRemote(继承psdi.mbo.MboRemote)接口。
示例:

package com.jxkj.app.receiption;

import java.rmi.RemoteException;
import java.util.Date;
import java.util.HashSet;

import org.apache.log4j.Logger;

import psdi.mbo.MboRemote;
import psdi.mbo.MboSet;
import psdi.mbo.MboSetRemote;
import psdi.mbo.MboValueInfo;
import psdi.mbo.StatusHandler;
import psdi.server.AppService;
import psdi.server.MXServer;
import psdi.txn.MXTransaction;
import psdi.util.MXApplicationException;
import psdi.util.MXApplicationYesNoCancelException;
import psdi.util.MXException;

import com.jxkj.app.receiption.virtual.CReceiptionStatusSet;
import com.jxkj.app.signature.ReadonlyServiceRemote;
import com.jxkj.mbo.JxStatefulMbo;

/**
* 类型:Receiption 说明:[接待方案]主对象类
*/
public class Receiption extends JxStatefulMbo implements ReceiptionRemote {

    private static Logger logger = Logger.getLogger(Receiption.class);

    private static HashSet skipFieldCopy = new HashSet();

    private static boolean isHashSetLoaded = false;

    MboRemote newReceiption;

    boolean isModified;

    boolean isEditHist;

    Receiption receiptionMbo;

    /**

      file:///C|/Documents and Settings/Administrator/桌面/maximo60开发指南.txt(第 18/24 页)[2010-9-28 9:01:18]

----------------------- Page 19-----------------------

      file:///C|/Documents and Settings/Administrator/桌面/maximo60开发指南.txt

     * @param ms
     * @throws RemoteException
     */
    public Receiption(MboSet ms) throws RemoteException {
        super(ms);
        isModified = false;
        isEditHist = false;
        // TODO Auto-generated constructor stub
    }

    /*
     * (non-Javadoc)
     * 返回关系RECEIPTIONSTATUS子对象集合
     * @see psdi.mbo.StatefulMbo#getStatusHistory()
     */
    protected MboSetRemote getStatusHistory() throws MXException, RemoteException {
        // TODO Auto-generated method stub
         //返回关系RECEIPTIONSTATUS的子对象集合
        return getMboSet("RECEIPTIONSTATUS");
    }

    /*
     * (non-Javadoc)
     *返回状态的值列表名称
     * @see psdi.mbo.StatefulMbo#getStatusListName()
     */
    public String getStatusListName() {
        // TODO Auto-generated method stub
           return "RECEIPTIONSTATUS";
    }
    /*
     *返回工作流名称
     */
    public String getProcess() {
        return "Receiption";
    }

    public void editHist() throws MXException, RemoteException {
        if (getBoolean("historyflag")) {
            setFlag(READONLY, false);
            MboSetRemote receiptionGuestSet = getMboSet("RECEIPTIONGUEST");
            receiptionGuestSet.setFlag(READONLY, false);
            isEditHist = true;
        } else {
            throw new MXApplicationException("receiption", "NoEditHist");
        }
    }
    /*
*返回状态处理者
*
*/

    protected StatusHandler getStatusHandler() {
        if (receiptionMbo != null)
            return new ReceiptionStatusHandler(receiptionMbo);
        else
            return new ReceiptionStatusHandler(this);
    }
    /*
*init方法,顾名思义就是做些初始化的东东
*如果不是新增记录,判断该记录的状态是否为“APPR”,如果是则该记录设为只读
*/
    public void init() throws MXException {
        super.init();
        if (!toBeAdded()) {
            try {
                String status = getInternalStatus();
                if (status.equals("APPR")) {
                    setFlag(READONLY, true);
                    MboSetRemote receiptionGuestSet = getMboSet("RECEIPTIONGUEST");
                    receiptionGuestSet.setFlag(READONLY, true);
                }
            } catch (RemoteException ex) {
                logger.error(ex.getMessage());
            }
        }
    }

    public void initRelationship(String relationName, MboSetRemote mboSet) throws MXException, RemoteException {
        super.initRelationship(relationName, mboSet);
        if ((mboSet instanceof ReceiptionGuestSet) && relationName.equals("RECEIPTIONGUEST")) {
            MXTransaction trn = getThisMboSet().getMXTransaction();
            int receiptionIndex = trn.indexOf(getThisMboSet());
            if (trn.indexOf(mboSet) > receiptionIndex)
                trn.setIndexOf(mboSet, receiptionIndex);
        }
        setRelatedMboEditibility(relationName, mboSet);
    }
     /*
*设置主记录和附属记录的输入模式READONLY=false|true
*
*/
    public void setRelatedMboEditibility(String relationName, MboSetRemote mboSet) throws MXException, RemoteException {
        if (toBeAdded())
            return;
        MboSetRemote relatedSet = mboSet;
        if (getBoolean("HistoryFlag") && !isEditHist) {
            setFlag(READONLY, true);
            if (!(relatedSet instanceof CReceiptionStatusSet))
                relatedSet.setFlag(READONLY, true);
        }
        if (relationName.equals("RECEIPTIONSTATUS"))
            relatedSet.setFlag(READONLY, true);
        if (relationName.equals("RECEIPTIONGUEST") && !getInternalStatus().equalsIgnoreCase("WAPPR"))
            relatedSet.setFlag(READONLY, true);
    }

    public void initFieldFlagsOnMbo(String attrName) throws MXException {
        super.initFieldFlagsOnMbo(attrName);
        if (toBeAdded()) {
            return;
        }

      file:///C|/Documents and Settings/Administrator/桌面/maximo60开发指南.txt(第 19/24 页)[2010-9-28 9:01:18]

----------------------- Page 20-----------------------

      file:///C|/Documents and Settings/Administrator/桌面/maximo60开发指南.txt

        try {
            ReadonlyServiceRemote readonlyRemote = (ReadonlyServiceRemote) MXServer.getMXServer().lookup("READONLY");
            readonlyRemote.setFieldEditibility(this, getThisMboSet().getApp(), getName(), attrName, getString("status"));
        } catch (RemoteException ex) {
            ex.printStackTrace();
        }
    }
     /*
     *新增记录,为某些字段赋值
     */
    public void add() throws MXException, RemoteException {
        Date currentDate = ((AppService) getMboServer()).getMXServer().getDate();
        setValue("enterby", getUserInfo().getPersonId(), NOACCESSCHECK | NOVALIDATION_AND_NOACTION);
        setValue("changeby", getUserInfo().getPersonId(), NOACCESSCHECK | NOVALIDATION_AND_NOACTION);
        setValue("changedate", currentDate, NOACCESSCHECK | NOVALIDATION_AND_NOACTION);
        setValue("historyflag", false, NOACCESSCHECK | NOVALIDATION_AND_NOACTION);
        setValue("status", getTranslator().toExternalDefaultValue("RECEIPTIONSTATUS", "WAPPR", this), NOACCESSCHECK | NOVALIDATION_AND_NOACTION);
        setValue("statusdate", currentDate, NOACCESSCHECK | NOVALIDATION_AND_NOACTION);
    }
    /*修改记录时调用modify方法
*如果有修改則更新changeby和changedate字段值
*
*/
    public void modify() throws MXException, RemoteException {
        if (!isModified) {
            isModified = true;
            setValue("changeby", getUserInfo().getPersonId(), NOACCESSCHECK);
        }
        setValue("changedate", MXServer.getMXServer().getDate(), NOACCESSCHECK);
    }
     /*
*复制主记录时也必须复制附属记录
*
*/
    public MboRemote duplicate() throws MXException, RemoteException {
        if (!isHashSetLoaded)
            loadSkipFieldCopyHashSet();
        newReceiption = copy();
        MboSetRemote currentDoclinksSetRemote = getMboSet("DOCLINKS");
        if (!currentDoclinksSetRemote.isEmpty())
            currentDoclinksSetRemote.copy(newReceiption.getMboSet("DOCLINKS"));
        MboSetRemote myPaymentLineSetRemote = getMboSet("RECEIPTIONGUEST");
        if (!myPaymentLineSetRemote.isEmpty())
            myPaymentLineSetRemote.copy(newReceiption.getMboSet("RECEIPTIONGUEST"));

        return newReceiption;
    }
    /*
*返回状态处理者
*
*/
    public void changeStatus(String status, Date date, String memo, long accessModifier) throws MXException, RemoteException {
        MXException caughtException = null;
        MboSet thisMboSet = (MboSet) getThisMboSet();
        Object params[] = { getString("RECEIPTIONNUM"), status };
        try {
            super.changeStatus(status, date, memo, accessModifier);
        } catch (MXApplicationYesNoCancelException mxyesnocancel) {
            throw mxyesnocancel;
        } catch (Throwable thrownObject) {
            caughtException = new MXApplicationException("receiption", "StatusChangeFailure", params, thrownObject);
            throw caughtException;
        }
        if (!status.equalsIgnoreCase(getString("status")))
            params = (new Object[] { getString("RECEIPTIONNUM"), getString("status") });

        thisMboSet.addWarning(new MXApplicationException("receiption", "StatusChangeSuccess", params));
    }
     /*
*删除主记录还需删除附属记录
*
*/
    public void delete(long access) throws MXException, RemoteException {
        getMboSet("RECEIPTIONGUEST").deleteAll();
        super.delete(access);
    }

    public void canDelete() throws MXException, RemoteException {
        if (getStatusHistory().count() > 1) {
            throw new MXApplicationException("receiption", "cannotdeletereceiption");
        }
    }
    /*
*把复制记录时跳过的字段加载进skipFieldCopy集合
*
*/
    private static void loadSkipFieldCopyHashSet() throws MXException, RemoteException {
        isHashSetLoaded = true;
        skipFieldCopy.add("CHANGEBY");
        skipFieldCopy.add("CHANGEDATE");
        skipFieldCopy.add("HISTORYFLAG");
        skipFieldCopy.add("ORGID");
        skipFieldCopy.add("SITEID");
        skipFieldCopy.add("RECEIPTIONNUM");
        skipFieldCopy.add("STATUS");
        skipFieldCopy.add("STATUSDATE");
    }

    protected boolean skipCopyField(MboValueInfo mvi) throws RemoteException, MXException {
        if (!isHashSetLoaded)
            loadSkipFieldCopyHashSet();
        return skipFieldCopy.contains(mvi.getName());
    }
}

 
2)    子对象的Mbo类
子对象Mbo类继承psdi.mbo.Mbo,实现psdi.mbo.MboRemote接口,以后开发,非工作流表可以继承com.jxkj.mbo. JxMbo(继承psdi.mbo.Mbo),实现com.jxkj.mbo. JxMboRemote(继承psdi.mbo.MboRemote)接口
package com.jxkj.app.receiption;

import java.rmi.RemoteException;
import java.util.HashSet;

      file:///C|/Documents and Settings/Administrator/桌面/maximo60开发指南.txt(第 20/24 页)[2010-9-28 9:01:18]

----------------------- Page 21-----------------------

      file:///C|/Documents and Settings/Administrator/桌面/maximo60开发指南.txt

import org.apache.log4j.Logger;

import psdi.mbo.MboRemote;
import psdi.mbo.MboSet;
import psdi.mbo.MboValueInfo;
import psdi.server.MXServer;
import psdi.util.MXApplicationException;
import psdi.util.MXException;

import com.jxkj.app.signature.ReadonlyServiceRemote;
import com.jxkj.mbo.JxMbo;

/**
* 类型:ReceiptionGuest
* 说明:[接待方案]子对象来宾信息类
*/
public class ReceiptionGuest extends JxMbo implements ReceiptionGuestRemote {

    protected static Logger logger = Logger.getLogger(ReceiptionGuest.class);
    private static HashSet skipFieldCopy = new HashSet();
    private static boolean isHashSetLoaded = false;

    /**
     * @param mboSet
     * @throws RemoteException
     */
    public ReceiptionGuest(MboSet mboSet) throws RemoteException {
        super(mboSet);
    }

    public void init()
        throws MXException
    {
        super.init();
    
        if(!toBeAdded())
        {
            setFieldFlag("RECEIPTIONNUM", READONLY, true);
        }
    }

    public void add()
        throws MXException, RemoteException
    {
        MboRemote owner = getOwner();

        setValue("receiptionnum", owner.getString("receiptionnum"), NOACCESSCHECK|NOVALIDATION_AND_NOACTION);
    }

    public void canDelete()
        throws MXException, RemoteException
    {
        Receiption receiption = (Receiption)getOwner();
        String status = receiption.getInternalStatus();
    
        if(!status.equals("WAPPR"))
        {
            Object params[] = {
                status
            };
            throw new MXApplicationException("receiption", "cannotdeleteline", params);
        }
    }

    public void initFieldFlagsOnMbo(String attrName) throws MXException {
        super.initFieldFlagsOnMbo(attrName);
        if (toBeAdded()) {
            return;
        }
    
        try {
            MboRemote receiption = (MboRemote) getOwner();
            ReadonlyServiceRemote readonlyRemote = null;
            readonlyRemote = (ReadonlyServiceRemote) MXServer.getMXServer().lookup("READONLY");
            readonlyRemote.setFieldEditibility(this,receiption.getThisMboSet().getApp(),getName(),attrName,receiption.getString("status"));
        } catch (RemoteException ex) {
            ex.printStackTrace();
        }
    }

    protected boolean skipCopyField(MboValueInfo mvi)
        throws RemoteException, MXException
    {
        if(!isHashSetLoaded)
            loadSkipFieldCopyHashSet();
        return skipFieldCopy.contains(mvi.getName());
    }

    private static void loadSkipFieldCopyHashSet()
        throws MXException, RemoteException
    {
        isHashSetLoaded = true;
        skipFieldCopy.add("ORGID");
        skipFieldCopy.add("SITEID");
        skipFieldCopy.add("RECEIPTIONNUM");
    }

    public void propagateKeyValue(String keyName, String keyValue)
        throws MXException, RemoteException
    {
        if(keyName.equalsIgnoreCase("receiptionnum"))
            setValue("receiptionnum", keyValue, NOACCESSCHECK|NOVALIDATION_AND_NOACTION);
    }

}

 
3)    状态对象Mbo
状态对象Mbo类必须继承psdi.mbo.Mbo,实现psdi.mbo.MboRemote接口,以后开发,非工作流表可以继承com.jxkj.mbo. JxMbo(继承psdi.mbo.Mbo),实现com.jxkj.mbo. JxMboRemote(继承psdi.mbo.MboRemote)接口

      file:///C|/Documents and Settings/Administrator/桌面/maximo60开发指南.txt(第 21/24 页)[2010-9-28 9:01:18]

----------------------- Page 22-----------------------

     file:///C|/Documents and Settings/Administrator/桌面/maximo60开发指南.txt

package com.jxkj.app.receiption;

import java.rmi.RemoteException;
import java.util.Vector;

import psdi.mbo.MboRemote;
import psdi.mbo.MboSet;
import psdi.util.MXApplicationException;
import psdi.util.MXException;

import com.jxkj.mbo.JxMbo;

/**
* 类型: ReceiptionStatus
* 说明:状态类
*/
public class ReceiptionStatus extends JxMbo implements ReceiptionStatusRemote {

    /**
     * @param mboSet
     * @throws RemoteException
     */
    public ReceiptionStatus(MboSet mboSet) throws RemoteException {
        super(mboSet);
        // TODO Auto-generated constructor stub
    }

    public void init() throws MXException {
        setFlag(READONLY, true);
        super.init();
    }

    public void add() throws MXException, RemoteException {
        MboRemote owner = getOwner();
        if (owner == null || !owner.getName().equals("RECEIPTION")) {
            throw new MXApplicationException("receiption", "addstatus");
        } else {
            setValue("receiptionnum", owner.getString("receiptionnum"), NOACCESSCHECK);
            setValue("status", owner.getString("status"), NOACCESSCHECK);
            setValue("changedate", owner.getDate("statusdate"), NOACCESSCHECK);
            setValue("changeby", owner.getString("changeby"), NOACCESSCHECK);
        }
    }

    public Vector getReceiptionStatusRecord() throws MXException, RemoteException {
        Vector v = new Vector();
        v.addElement(getMboValueData("changedate").getData());
        v.addElement(getMboValueData("memo").getData());
        v.addElement(getMboValueData("status").getData());
        v.addElement(getMboValueData("changeby").getData());
        v.addElement(getMboValueData("receiptionnum").getData());
        v.addElement("");
        return v;
    }

}

4)    虚拟状态表对象的Mbo类
虚拟状态表对象Mbo类必须继承psdi.mbo.NonPersistentMbo,实现psdi.mbo.NonPersistentMboRemote接口。
示例:

package com.jxkj.app.receiption.virtual;

import java.rmi.RemoteException;

import psdi.mbo.MboSet;
import psdi.mbo.NonPersistentMbo;
import psdi.server.MXServer;
import psdi.util.MXException;

/**
* 类型:CReceiptionStatus
* 说明:虚拟状态类
*/
public class CReceiptionStatus extends NonPersistentMbo implements CReceiptionStatusRemote {

    /**
     * @param ms
     * @throws MXException
     * @throws RemoteException
     */
    public CReceiptionStatus(MboSet ms) throws MXException, RemoteException {
        super(ms);
        // TODO Auto-generated constructor stub
    }

    public void add() throws MXException, RemoteException {
        super.add();
        java.util.Date currentDT = MXServer.getMXServer().getDate();
        setValue("statdate", currentDT, 11L);
    }
}

7.1.4    StatusHandler类
StatusHandler类必须继承psdi.mbo.StatusHandler。
示例:

package com.jxkj.app.receiption;

import java.rmi.RemoteException;
import java.util.Date;

import psdi.mbo.StatefulMbo;
import psdi.mbo.StatusHandler;
import psdi.security.ProfileRemote;
import psdi.util.MXAccessException;
import psdi.util.MXApplicationException;
import psdi.util.MXException;

/**
* 类型: 说明:
*/
public class ReceiptionStatusHandler extends StatusHandler {

     file:///C|/Documents and Settings/Administrator/桌面/maximo60开发指南.txt(第 22/24 页)[2010-9-28 9:01:18]

----------------------- Page 23-----------------------

      file:///C|/Documents and Settings/Administrator/桌面/maximo60开发指南.txt

    private StatefulMbo parent;

    private String WAPPR;

    private String APPROVE;

    private String CLOSE;

    private String CANCEL;

    static final int Wappr = 0;

    static final int Appr = 1;

    static final int Close = 2;

    static final int Can = 3;
    //对象状态转换关系矩阵
    public static boolean statusChangeMatrix[][] = { { false, true, true, true }, { true, false, true, true }, { false, true, false, false }, { false, false, false, false } };

    /**
     * @param sm
     */
    public ReceiptionStatusHandler(StatefulMbo sm) {
        super(sm);
        parent = null;
        WAPPR = "WAPPR";
        APPROVE = "APPR";
        CLOSE = "COMP";
        CANCEL = "CAN";
        parent = sm;
        // TODO Auto-generated constructor stub
    }

    /*
     * (non-Javadoc)
     * 检查状态变化权限
     * @see psdi.mbo.StatusHandler#checkStatusChangeAuthorization(java.lang.String)
     */
    public void checkStatusChangeAuthorization(String desiredExternalStatus) throws MXException, RemoteException {
        String desiredMaxStatus = parent.getTranslator().toInternalString("RECEIPTIONSTATUS", desiredExternalStatus);
        checkUserSecurity(desiredMaxStatus);
        // TODO Auto-generated method stub

    }
    /*
     * (non-Javadoc)
     * 把状态转换为关系矩阵下标
     * @see     
*/

    static int convertStatusToInt(String internalStatus) {
        if (internalStatus.equalsIgnoreCase("WAPPR"))
            return 0;
        if (internalStatus.equalsIgnoreCase("APPR"))
            return 1;
        if (internalStatus.equalsIgnoreCase("COMP"))
            return 2;
        return !internalStatus.equalsIgnoreCase("CAN") ? -1 : 3;
    }
     /*
     * (non-Javadoc)
     * 通过关系矩阵,判断状态变化是否合法,如果非法则抛出异常
     * @see     
*/
    private void possibleStatusChange(String currentMaxStatus, String desiredMaxStatus) throws MXException, RemoteException {
        if (!statusChangeMatrix[convertStatusToInt(currentMaxStatus)][convertStatusToInt(desiredMaxStatus)])
            throw new MXApplicationException("receiption", "invalidstatuschange");
    }
     /*
     * (non-Javadoc)
     * 检查用户的权限
     * @see     
*/
    public void checkUserSecurity(String desiredMaxStatus) throws MXException, RemoteException {
        String application = parent.getThisMboSet().getApp();
        if (application == null || application.equals(""))
            return;
        String optionName = null;
        if (desiredMaxStatus.equals("WAPPR"))
            optionName = "UNAPPROVE";
        else if (desiredMaxStatus.equals("APPR"))
            optionName = "APPROVE";
        else if (desiredMaxStatus.equals("CAN"))
            optionName = "CANCEL";
        else if (desiredMaxStatus.equals("COMP"))
            optionName = "COMPLETE";

        ProfileRemote p = parent.getMboServer().getProfile(parent.getUserInfo());
        if (optionName == null || !p.getAppOptionAuth(application, optionName, parent.getString("siteid")))
            throw new MXAccessException("access", "notauthorized");
    }
    /*
     * (non-Javadoc)
     * 判断两个状态能否进行转换
     * @see     
*/

    public void canChangeStatus(String currentStatus, String desiredStatus, long accessModifier) throws MXException, RemoteException {
        String currentMaxStatus = parent.getTranslator().toInternalString("RECEIPTIONSTATUS", currentStatus);
        String desiredMaxStatus = parent.getTranslator().toInternalString("RECEIPTIONSTATUS", desiredStatus);
        possibleStatusChange(currentMaxStatus, desiredMaxStatus);
    }
    /*
     * (non-Javadoc)
     * 状态发生变化时,执行相应的操作并更新状态日期statusdate字段值
     * @see     
*/
    public void changeStatus(String currentStatus, String desiredStatus, Date date, String memo) throws MXException, RemoteException {
        if (date.getTime() < parent.getDate("statusdate").getTime())
            throw new MXApplicationException("receiption", "statusdate");
        String currentMaxStatus = parent.getTranslator().toInternalString("RECEIPTIONSTATUS", currentStatus);

      file:///C|/Documents and Settings/Administrator/桌面/maximo60开发指南.txt(第 23/24 页)[2010-9-28 9:01:18]

----------------------- Page 24-----------------------

      file:///C|/Documents and Settings/Administrator/桌面/maximo60开发指南.txt

        String desiredMaxStatus = parent.getTranslator().toInternalString("RECEIPTIONSTATUS", desiredStatus);
        if (desiredMaxStatus.equals(WAPPR))
            unapprove(currentMaxStatus, desiredStatus);
        else if (desiredMaxStatus.equals(APPROVE))
            approve(currentMaxStatus, desiredStatus);
        else if (desiredMaxStatus.equals(CLOSE))
            close(currentMaxStatus, desiredStatus);
        else if (desiredMaxStatus.equals(CANCEL))
            cancel(currentMaxStatus, desiredStatus);

        parent.setValue("statusdate", date, NOACCESSCHECK);
    }
    /*
     * (non-Javadoc)
     * 要跳到APPROVE时执行的操作,这里是更新status字段值为目标状态
     * @see     
*/
    private void approve(String currentMaxStatus, String desiredStatus) throws MXException, RemoteException {
        parent.setValue("status", desiredStatus, NOACCESSCHECK);
    }
     /*
     * (non-Javadoc)
     * 要跳到WAPPR时执行的操作,这里是更新status字段值为目标状态
     * @see     
*/
    private void unapprove(String currentMaxStatus, String desiredStatus) throws MXException, RemoteException {
        parent.setValue("status", desiredStatus, NOACCESSCHECK);
    }
      /*
     * (non-Javadoc)
     * 要跳到CLOSE时执行的操作,这里是更新status和historyflag字段值为目标状态
     * @see     
*/
    private void close(String currentMaxStatus, String desiredStatus) throws MXException, RemoteException {
        parent.setValue("historyflag", true, NOACCESSCHECK);
        parent.setValue("status", desiredStatus, NOACCESSCHECK);
    }
     /*
     * (non-Javadoc)
     * 要跳到CANCEL时执行的操作,这里是更新status和historyflag字段值为目标状态
     * @see     
*/
    private void cancel(String currentMaxStatus, String desiredStatus) throws MXException, RemoteException {
        parent.setValue("historyflag", true, NOACCESSCHECK);
        parent.setValue("status", desiredStatus, NOACCESSCHECK);
    }
}

      file:///C|/Documents and Settings/Administrator/桌面/maximo60开发指南.txt(第 24/24 页)[2010-9-28 9:01:18]

posted on 2012-03-28 14:48 cpegtop 阅读(6863) 评论(0)  编辑  收藏

只有注册用户登录后才能发表评论。


网站导航: