2009年7月31日星期五

CMSEntity之六,内容提交和产品定价的规则

两个重要概念:
1. 定价方法(price method):
  • 免费试用(Demo):用户免费使用
  • 购买(Purchase):一次性购买
  • 订购(Subscription):包月

2. 定价基础(price basis):
  • 使用次数(number of uses):应用可使用的最大次数
  • 使用期限(expiration data):到期截止日
  • 使用天数(number of days):可使用的天数
  • 使用时长(elapsed time):应用在终端上可以使用的时长,以分钟为单位

产品以这两个概念为定价的基础,剩下两个辅助概念,一个是price,一个是price value,这些就是四元组。price表示实际的费用,例如某个产品是5元10次,那么price就是5元,而price value就是10。

规则:
  • 三种定价方法相互独立,也就是说给某个内容定价时,可以使用其中的一个,两个,或者三个。
  • 选择免费试用(Demo)方法时
    • 只有三种定价基础可以用,即使用次数,使用天数,使用时长。使用期限不可用
    • 在三种可用的定价基础中,只能选择其中一种,其缺省值为不超过10次,不超过10分钟或不超过一天。
  • 在选择订购(subscription)定价方法时
    • 定价基础是可以忽略的
  • 在选择购买(purchase)定价方法时
    • 四种定价基础(使用次数,使用期限,使用天数,使用时长)全部可用
    • 虽然四种定价基础都可用,但是只能选择其中的一种使用,例如,如果选用使用次数,那就不能再选择使用天数
    • 对 于某个被选择的定价基础,最多可用三个price value(这一块可用参考代码,常量PURCHASE_PRICE_OPTION_SIZE应该就是这么来的),例如:5元包10天,10元包60天, 和20元无限使用的三个产品是允许的。但是,5元包10天,10元包60天,15元包100天和20元无限使用的四个产品是不允许的。
    • 无限使用的购买适用于任意一种定价基础。例如:使用次数(无限次),使用天数(无限天),使用时长(无限时长),使用期限(无限期限)。

合法产品示例:

内容1有4个产品:

* 产品11:免费试用(Demo)1天
* 产品12:2元包月
* 产品13:2元包10天
* 产品14:20元无限使用

内容2有5个产品:

* 产品21:免费试用(Demo)10分钟
* 产品22:3元包月
* 产品23:2元包5次
* 产品24:5元包15次
* 产品25:20元无限使用


非法产品的示例:

内容3有4个产品:

* 产品31:免费试用(Demo)15次
* 产品32:2元包月
* 产品33:2元包10天
* 产品34:20元无限使用

内容4有4个产品:

* 产品41:免费试用(Demo)10分钟
* 产品42:3元包月
* 产品43:2元包5次
* 产品44:5元包10天

内容5有5个产品:

* 产品51:3元包月
* 产品52:2元包1小时
* 产品53:5元包10小时
* 产品54:10元包40小时
* 产品55:20元无限使用

2009年7月30日星期四

CMSEntity之五,price plan的生成

接昨日:
prepareMfgPricePlan用于构建manufacture price plan文件,它会调用createMfgPriceMethod方 法,前面提到了,方法createPriceMethod会创建price method,这些信息会被manufacturer price plan文件和operation price plan文件使用,当createPriceMethod创建好price method后,这些信息保存在ProductPriceMethodVO,查看ProductPriceMethodVO的成员可以,其实里面放的就是四元组:price method,price value,price basis和price。同时createPriceMethod也会调用setPriceMethod将这些信息保存到ProductVO(ProductVO有一个ProductPriceMethodVO型的成员priceMethod)。

再 回到prepareMfgPricePlan,它调用createMfgPriceMethod方法,createMfgPriceMethod其实就是 从ProductVO中得到ProductPriceMethodVO信息,然后将这些信息分别填到MfgPriceMethodTypeVO中去。 prepareMfgPricePlan然后就是一个逻辑:因为调用createMfgPriceMethod后得到一个 MfgPriceMethodTypeVO对象mpmo,然后用这个对象的Method_type作为一个key,去mpmoMap里去查找,看是能查 到,如果能查到,将查到的值赋给prevMpmo。

为了清楚地描述这个逻辑,现在做下面的定义:
当前的MfgPriceMethodTypeVO对象:mpmo
原有的MfgPriceMethodTypeVO对象:prevMpmo(如果原有的对象存在,这是用Method_type作为一个key,去mpmoMap里查找的)
四元组:price method,price,price value,price basis
price mothod可能的值有:Demo,Purchase,Subscription
price valude可能的值有:数值(1,2,3等),UNLIMITED
price basis可能的值有:USES,TIME,DAYS
OPTION:是Manufacturer price plan文件的一个tag,它包含四元组的price和price value两项。

逻辑:
1,如果当前的product value是UNLIMITED,那么将当前的productVO和method type存放到一个map里:productsBasisUnlimited.put(key, pv);

2,判断是否有prevMpmo,如果有,进入步骤3,如果没有,直接到步骤5。

3.a, 当prevMpmo存在时,如果当前的method type是Purchase,将optionSize赋值为3:optionSize = Constants.PURCHASE_PRICE_OPTION_SIZE;(这里需要解释的是为什么常量 PURCHASE_PRICE_OPTION_SIZE为3而不是别的值,今天看到“关于BREW内容提交和产品定价的规则说明”邮件才知道,这是 BREW规定的。“对于任意一个被选中的定价基础,BREW允许最多三个定价基础值”,所以常量PURCHASE_PRICE_OPTION_SIZE的 值为3).

3.b,当prevMpmo存在时,如果当前的method type不是Purchase,将optionSize赋值为1:optionSize = Constants.DEMO_PRICE_OPTION_SIZE(解释见上)。

4,判读mpmo和prevMpmo的price basis是否相等,相等进入4.1,不等进入4.2

4.1.a,获取prevMpmo的OPTION的size,如果大于optionSize,报错

4.1.b, 如果小于optionSize,调用方法checkDuplicatePriceValue判断prevMpmo和mpmo是否相等(也就是判断两者包含 的四元组是否完全相等),如果相等就抛出异常。如果不等,将当前mpmo的OPTINO加入到原有prevMpmo的OPTION 中:prevMpmo.getOPTION().addAll(mpmo.getOPTION());

4.2.a,price basis不相等,调用方法updateBasisUnlimited,这个方法判断prevMpmo和mpmo的price basis是否是UNLIMITED,如果是就将其price basis赋给另一方,如果都不是,返回false。

4.2.b,如果updateBasisUnlimited返回true,将当前mpmo的OPTINO加入到原有prevMpmo的OPTION中:prevMpmo.getOPTION().addAll(mpmo.getOPTION());否则报错。

5,将当前mpmo加入map:mpmoMap.put(key, mpmo);

逻辑完后,prepareMfgPricePlan会调用ProductParserImpl类的方法prepareMfgPricePlanMeta去生成meta文件,到此为止。

prepareMfgPricePlan 执行完毕后,返回到processCntProductAssocList,它会调用submitMfgPricePlan方法,这个方法最终会调用 BMCClientImpl类的createMfrPricePlan,这个方法的功能是:This method will invoke the BMC service and submits the manufacturer price plan。到此为止,manufacturer price plan文件的生成及提交就完成了。

processCntProductAssocList继续调用prepareOprPricePlan来生成operation price plan文件。prepareOprPricePlan调用createOprPriceMethod来 说生成price method,这个方法和createMfgPriceMethod(如前述)的作用是一样的。prepareOprPricePlan后面的工作就很简 单了。这里有个问题,相对于prepareMfgPricePlan,prepareOprPricePlan的逻辑非常简单,根本原因就是 MfgPriceMethodTypeVO和OprPricePlanMethodTypeVO的成员虽然很相似,都是四元组,但是两者有一个很大的区别 是:OprPricePlanMethodTypeVO的PricePointTypeVO变量是一个值,而MfgPriceMethodTypeVO中 是一个PricePointTypeVO的List。这导致了prepareMfgPricePlan比prepareOprPricePlan要简单得 多。

2009年7月29日星期三

CMSEntity之四,三类文件的处理

ProductHandler类是真正从product,product content和charging info转换为price plan,入口可以认为是processPricePlans方法。

首 先它调用getUnprocessedCntProductAssoc,这个方法的功能是:1.Get Unprocessed Content and Product associate VO from DB 2.Sort the unprocessed list。这个方法涉及到了ContentProductAssocVO,这里有个机制去判断一个ContentProductAssocVO是否已经被 处理过,逻辑上应该是先比较几个ID:IsmpContentId,IsmpProductId和OpFlag,如果相同,再比较时间戳。但是具体的逻辑 没细看。

获得Content and Product associate VO list后,processPricePlans继续调用processCntProductAssocList, 这个方法的功能是:Fetch all the content and product pair in the content_product_mapping table for this particular content_id。注意这里面提到了CONTENT_PROD_MAP table,这个表很重要。processCntProductAssocList方法调用fetchContent来获得ContentItemVO,注意fetchContent的参数是contentID。

然后processCntProductAssocList调用fetchProcducts, 这个方法有点复杂,它用参数返回好几个map(cntProducts,deletedCntProdMap和omittedCntProdMap,把哪 些product放到哪一个map里是更加opflag来判断的,另外,处理出错的情况都放到omittedCntProdMap里去。)。这个方法会调 用createPriceMethod,这个方法非常重要,它用来生成price method,在manufacture price plan和operation price plan里都能看见(method标签),它的参数有ChargingPolicyVO和ProductVO,前者保存的是电信的收费信息。该方法首先得到charg info的收费方式,在电信文档的附录D中有描述,包括BREW系统原有计费策略和与之相应的ISMP产品计费策略。这些策略一共有九种,但是在createPriceMethod里只处理了5种情况,不知道为什么。

在 fetchProducts的最后有一个逻辑,当OpFlag为delete时,把product放入deletedCntProdMap,如果 OpFlag不是delete,那就是add,但是在之前还要进行判断,如果要add的项也被包含在deletedCntProdMap(两者的 productID相同,也就是一个product既已经被包括在deletedCntProdMap,现在又要将其add),那么就要判断add的项和 delete的项两者的时间戳,如果要add项的时间戳要早于要delete项的时间戳,那就什么也不干(表示这个product最终是要被删除的),反 之,就将给product加入到cntProducts中。

processCntProductAssocList会调用fetchProducts两次,然后processCntProductAssocList调用prepareMfgPricePlan方 法,它的功能是:Prepare the MFG Price plan and generate the meta file. The ISMP price plan to BMC price plan mapping logic are locate inside this method. 说明这个方法很重要,manufacturer price plan文件就是由它构建的。

2009年7月28日星期二

CMSEntity之三,谈话整理

昨天下午谈话的整理:
电信这边的产品信息包括:product info,product content和charging info。电信的收费信息是针对product而言的,也就是一个产品它有计费信息,而不是一个内容或者一个电信item有它的计费信息。而BREW这 边,计费信息是针对manufacturer partner number的,每个manufacturer partner number下面包含有多个item,一个manufacturer partner number就相当于一个组,包含多个BREW item,计费信息就是针对这个组的。目前是把manufacturer partner number和电信那边的content视为等价,但其实两者是不同概念。

price plan是BREW这边的概念,它是由product info,product content和charging info这三个文件导出的,四元组:price basis,price method,price value和就包含在price plan中,所以price plan是非常重要的。

Meta.xml和item.zip一起再压缩成一个zip给BMC(这个Meta.xml和item.zip最好能看看里面的内容)。

数 据库的几个表,ISMP_Content,ISMP_Item等等(ISMP Content number什么的,作为key,这个也不知道是什么东西),这个没搞清楚,还有对应product info,product content和charging info每个文件都有一个表,这些表要弄清楚。

对BREW手机和ADS来说,catalog是有多个 的,每个catalog是针对语言来说的,例如英语有英语的一个catalog,汉语有汉语的一个catalog,其它语言有其自己的catalog。每 个catalog可以想象其为一颗树,和pc机上的目录结构是一样的,catalog下有category,也有subcatalog,catalog下 也可以有item,subcatalog下有item等等。

manufacture price plan和operation price plan是高通的遗留东西,但是现在还在使用,两者的区别是operation price plan有change list,但是manufacture price plan没有。

在CMSEntity里的dao包中,有关的表有:
PRODUCT_INFO table,PRODUCT_CHARGE_INFO table,PRODUCT_CHARGE_MODE table,CONTENT_PROD_MAP table,ISMP_ITEM table,ISMP_ITEM_MODELS table,ISMP_ITEM_LANGUAGES table,CHANGE_LIST table,Ismp_Region table等等,目前重点关注PRODUCT_INFO table,PRODUCT_CHARGE_INFO table,PRODUCT_CHARGE_MODE table,CONTENT_PROD_MAP table。

2009年7月27日星期一

CMSEntity之二

com.qualcomm.bss.bsg.cms.job.ContentProcessorJob.execute会调用 com.qualcomm.bss.bsg.cms.process.ContentHandler.invokeProcess,我觉得 ContentHandler应该是真正干活的,它来解析map文件并把内容保存到数据库中。但是 ContentHandler.invokeProcess很简单,它调用了 ContentHandler.commonStorageHandling,在这个方法中对ISMPItemVO,ContentItemVO进行了一 番操作,但是也没看出头绪。

TerminalInfoLoadJob:
com.qualcomm.bss.bsg.cms.servicelayer.BSGCMSServlet.init->com.qualcomm.bss.bsg.cms.job.TerminalInfoLoadJob.execute->com.qualcomm.bss.bsg.cms.job.TerminalInfoLoadJob.loadData

ContentFetcherJob:
com.qualcomm.bss.bsg.cms.servicelayer.BSGCMSServlet.init->com.qualcomm.bss.bsg.cms.job.ContentFetcherJob.execute->com.qualcomm.bss.bsg.cms.process.ContentAdaptor.invokeProcess
->com.qualcomm.bss.bsg.cms.CDParserImpl.parseCDFile

ContentProcessorJob:
com.qualcomm.bss.bsg.cms.servicelayer.BSGCMSServlet.init->com.qualcomm.bss.bsg.cms.job.ContentProcessorJob.execute->com.qualcomm.bss.bsg.cms.process.ContentHandler.invokeProcess->
com.qualcomm.bss.bsg.cms.process.ContentHandler.commonStorageHandling

ProductInfoFetchJob:
com.qualcomm.bss.bsg.cms.servicelayer.BSGCMSServlet.init->com.qualcomm.bss.bsg.cms.job.ProductInfoFetchJob.execute->com.qualcomm.bss.bsg.cms.process.prodAdaptor.processProductFiles

ProductAdaptor里的方法大有可为,很多事情都是在ProductAdaptor里 面做的,看ProductAdaptor类前面的解释,它的功能包括:1,获取product info文件并保存到本地文件夹;2,解析product info文件并保存到数据库;3,获取product content文件并保存到本地文件夹;4,解析product content文件并将数据保存至数据库;5,获取charge info文件并保存到本地文件夹;6,解析charge info文件并将数据保存至数据库;
由此可见,三个map文件都是在ProductAdaptor类里处理的,所以有必要对ProductAdaptor类中的每个方法都细读。

ProductAdaptor.processProductFiles, 这个方法的功能是用ftp获取三个map文件,即product info,product content和charging info。这个方法里用到了类ProductFtpHandler,并对ProductParser类进行了实例化。ProductFtpHandler 是用来获取相应的map文件的,调用它的fetchProductInfoFilesfetchProductContentFilesfetchChargingInfoFiles就能获得相应的文件。每当获得相应的文件后,processProductFiles会调用方法来解析获得的文件,这些方法包括processProductInfoFileprocessProductContentFilesprocessChargingFiles,从名字就很好判断它们的作用。

前面提到processProductFiles实例化了ProductParser,这个类顾名思义,是用来解析product info文件的,但是看这个类的解释,又不仅仅是。ProductParser类只是一个接口,它的实现类是ProductParserImpl, 这个类最前面的注释说:“This class is used to parse product info ,Product content mapping , charging policy info files. Also creates price plan xml files.”,从这段注释可知这个ProductParserImpl不仅仅是解析product info文件,它把三个map文件都解析了,同时生成了price plan文件。前面提到的processProductInfoFileprocessProductContentFilesprocessChargingFiles方法都使用了ProductParser的实例来解析相应的文件。

ProcessProductInfoFile 先是调用了ProductParserImpl.parseProductFile解析product info文件,它的返回值是ProductInfoVO,然后ProcessProductInfoFile再调用 ProductDAO.addProductInfo将ProductInfoVO的信息写入到数据库中。
processProductContentFiles 处理product content文件,它的处理过程和ProcessProductInfoFile差不多,先是调用 ProductParserImpl.parseProductContentFile解析product content文件,返回值是ProductContentVO,在将ProductContentVO的信息保存到数据库之 前,processProductContentFiles还调用了applyProductContent方法,这个方法是“used to apply products to contents”,不知道是什么意思。但是看代码,这里是生成product和content的关系,这些关系都存放在contentProductAssocVO,这是一个很重要的对象,后面的操作要经常使用这个对象。然后ProcessProductInfoFile再调用ProductDAO.applyProductContent将ProductContentVO的信息写入到数据库中。
processChargingFiles的流程和前两个相似,不赘述。

ProductProcessJob:
com.qualcomm.bss.bsg.cms.servicelayer.BSGCMSServlet.init->com.qualcomm.bss.bsg.cms.job.ProductProcessJob.execute->com.qualcomm.bss.bsg.cms.process.ProductHandler.processPricePlans

ProductHandler类是生从电信的那一套(也就是product,content,item和charging info)转换成BREW识别的一套(item和price handle)的关键。具体的实现与数据库非常相关,目前暂时还没研究。

ReleaseProcessJob:
com.qualcomm.bss.bsg.cms.servicelayer.BSGCMSServlet.init->com.qualcomm.bss.bsg.cms.job.ReleaseProcessJob.execute->com.qualcomm.bss.bsg.cms.process.ReleaseHandler.invokeProcess

MasterSwitchJob:
com.qualcomm.bss.bsg.cms.servicelayer.BSGCMSServlet.scheduleMasterSwitch->

FeedBackFileUpLoaderJob:
com.qualcomm.bss.bsg.cms.servicelayer.BSGCMSServlet.scheduleFeedBackUpLoadProcess->com.qualcomm.bss.bsg.cms.job.FeedBackFileUpLoaderJob

2009年7月24日星期五

CMSEntity之一,各种Job和VO

contentFetcherJob
ContentProcessorJob

ProductInfoFetchJob
ProductProcessJob

com.chinatelecom.ismp.contentpublish.req包的类ContentSyncNotifyReq

com.chinatelecom.ismp.contentpublish.ContentPublishedReqAdapter
com.chinatelecom.ismp.contentpublish包里的方法ContentPublishedReqAdapterSoapBindingImpl::contentSyncNotify

前 面的关系有点乱,到现在还没理清,按流程应该是ISMP先给BSG发一个contentSyncNotify(一个SOAP call),BSG收到这个notify后去解析它的内容,获得content description文件的存放地址和目录,但是现在还不知道是在哪里处理这个notify的,本以为是在 com.qualcomm.bss.bsg.cms.servicelaye.BSGWebServiceServlet处理这个notify的,但是看 了这个类的doGet方法,感觉这个方法没有处理notify。CMSWebServices和CMSEntity两个工程里面都没找到,这个暂且放下, 以后再找找。

目前看com.chinatelecom.ismp.contentpublish。ContentPublishedReqAdapterSoapBindingImpl::contentSyncNotify是处理notify的(但不知道它是如何被调用的,好像用了一个axis2的东西,google了一下,这是Apache的一个包,但是它是干什么用的没细看)。
方法contentSyncNotify使用了contentSyncNotifyReq, 这个类其实无甚特别,但是其中有一段代码搞得我很迷惑:static{... ...},这段代码和org.apache.axis.description有关,不知道是干嘛的,留到后面再研究。然后 contentSyncNotify调用saveContentSyncInfo将得到的信息保存到数据库中,这个应该是content description文件的存放地址和目录。

com.qualcomm.bss.bsg.cms.parser是一个接口,类CDParserImpl实现了这个接口,里面有个方法:parseCDFile,这个方法就是用来解析content description文件的。
com.qualcomm.bss.bsg.cms.process.ContentAdaptor类中的方法:invokeProcess,调用了parseCDFile。
然 后com.qualcomm.bss.bsg.cms.job.ContentFetcherJob的方法execute中会调用 contentAdaptor.invokeProcess。这个ContentFetcherJob是从StatefulJob继承的类,也就是它是一 个Quterz的类,周期性地执行,
在com.qualcomm.bss.bsg.cms.servicelayer.BSGCMSServlet的init方法中会创建ContentFetcherJob,并对它进行调度。

所 以这几步的流程 是:com.qualcomm.bss.bsg.cms.servicelayer.BSGCMSServlet.init->com.qualcomm.bss.bsg.cms.job.ContentFetcherJob.execute->com.qualcomm.bss.bsg.cms.process.ContentAdaptor.invokeProcess
->com.qualcomm.bss.bsg.cms.CDParserImpl.parseCDFile。

在 ContentAdaptor类里有个方法fetchFile,这个方法其实就是从给定的地址中用FTP去取文件,invokeProcess调用 fetchFile去获取content description文件,content description文件的地址,在前面提到,content description文件的存放地址和目录已经保存在数据库中了。

content description文件解析完后,ContentAdaptor::invokeProcess会调用fetchZipFile去获取zip文件,这 些zip文件就是product_info.map,content_product.map和charge_info.map文件了。文件被取回 后,ContentAdaptor::invokeProcess还调用了:
batchStatusVO.setProcStatCodeID(Constants.BATCH_STATUS_SAVED);
updateBatchStatus(batchStatusVO);
这 两个调用貌似很重要,因为zip文件取回后就要进入下一步的处理,即将这三个map文件解析并将相应的内容填到数据库中,但是处理三个map文件也是一个 job,即ContentProcessJob,这个job也是在 com.qualcomm.bss.bsg.cms.servicelayer.BSGCMSServlet.init被创建初始化并调度的。也就是说, 它一直周期性地试图去处理三个map文件,但是并不是时时刻刻都有map文件需要处理(因为不是每时每刻都有产品要提交到BMC上去),所以当有新的 map文件被取回后,必须要有一种方法通知ContentProcessJob,现在有新的map文件需要处理了。这个方法应该就是 ContentAdaptor::invokeProcess在取回map文件后,向数据库里写了某些信息,就相当于置了某些标志位,然后 ContentProcessJob在处理过程中首先是查询数据库,获得信息得知是否有新的map文件需要处理。

com.qualcomm.bss.bsg.cms.job.ContentProcessorJob
com.qualcomm.bss.bsg.cms.process.invokeProcess
com.qualcomm.bss.bsg.cms.process.getSuitableBatch

ISMPItemVO
ContentItemVO

2009年7月22日星期三

ISMPEntity之三,2.x和3.x对包月非包月业务的处理流程

包com.qualcomm.bss.bsg.ismpentity.ismpcore中的类ProductPriceObject值得关注,它里面包含了几乎所有重要信息:priceHandle,productID, priceMethod,priceBasis,optionPrice(就是pricevalue),regionId,contentId和optionValue。所以得到ProductPriceObject的实例就可以知道productID等信息。
在 包com.qualcomm.bss.bsg.ismpentity.devices的类Device中有个方 法:getProductPriceObject,可以用它获得ProductPriceObject,getProductPriceObject其实 是去查询数据库来获得ProductPriceObject:
productPriceObject = operationalDataDAO.getPriceHandleMap(String.valueOf(priceHandle), itemId, regionId);

如 果在数据库里查找不到,那么getProductPriceObject会去ISMPConfig里查找postactivition的地 址:String strPostACtivationIPANdURL = ISMPConfig.postActivationURL,根据这个地址,调用方法submitRequest,实际上是去这个地址去访问,返回值是个 字符串,里面包含了ProductPriceObject的所有信息。

3.x手机,下载非包月应用,处理的流程:
1,用户选择好应用后,点击下载
2,手机发出下载鉴权请求给ADS
3,ADS将请求发给BSG
4,经过BSG的router,最终ISMPEntity收到鉴权请求。
5,RequestHandler::doGet->ISMPEntity::invokeService->Locator::locateDeviceHandle->Device::handleRequest
6,Device::handleRequest根据请求的类型来做相应处理,有三种类型的请求:
public enum RequestTypeStatusCodes {
PurAuth,
MsgDownloadAck,
DeleteAck
}
因为是非包月下载请求,所以这里是PurAuth。
7,用Device::getProductPriceObject获得ProductPriceObject对象,该包含了pricehandle,productID等等信息。
8,进入PurAuth处理流程,判读是否包月(这里是非包月),进入非包月处理分支,获得PurchaseAuthorizationHandlerImpl对象。
9, 进入PurchaseAuthorizationHandlerImpl::handleRequest方法,生成 messageID(messageID是联系request和response的桥梁,ISMPEntity会有多个不同的request放在 queue里并发送给ISMP,同时ISMP也会有多个不同的response,request和response必须成对出现,有request必须有 response,某对request和response之间就靠messageID联系,它们必有相同的messageID)并和其它信息 (ismi,itemID,pricehandle等)一起保存到数据库。
10,调用preparePDU构建PDU,然后调用PDURequestHandlerInterface::sendPDU发送PDU。

3.x手机,下载包月应用,处理的流程:
前7步和3.x非包月相同。
8, 进入PurAuth处理流程,判读是包月,进入包月处理分支,获得CreateSubscriptionHandlerImpl对象。
9,进入CreateSubscriptionHandlerImpl::handleRequest方法,包月的创建是用SOAP的,所以调用了方法prepareSOAPRequest去构建并发送SOAP request。

当 ISMP返回成功后,3.x下载包月应用的流程应该和下载非包月的流程一样,再次进入 PurchaseAuthorizationHandlerImpl::handleRequest方法去发送PDU,但是3.x如果再次进入 PurchaseAuthorizationHandlerImpl的处理流程,目前还没有看出来(参考电信文档第8.3.2节"有下载鉴权的包月应用下 载",BSG和ISMP之间是先用SOAP发送了createSubscriptionReq和createSubscriptionResp,然后再和 下载非包月应用一样,发送AuthPrice request和response。我估计因为SOAP还是建立在http协议之上的,所以当ISMP发送createSubscription response给BSG后,ISMPEntitiy还是先进入RequestHandler::doGet,后面的流程就和下载非包月一样了)。

2.x手机,下载非包月应用,处理流程:
前10步和3.x非包月相同。
11,AuthPrice的request PDU发送后,PurchaseAuthorizationHandlerImpl::handleRequest返回到TwoXDeviceImpl::handleRequest。
12, 调用Device::duplicateMsgDownloadAckCheck,这个方法是用来验证MsgDownloadAck是否是已经发送过的 (duplicated),如果是,表明MsgDownloadAck已经被处理过,不用再处理。如果不是,到13步。
13,进入DownloadConfirmationHandlerImpl,调用DownloadConfirmationHandlerImpl::handleRequest方法,发送AuthPricecnfm的PDU。