WS-Security 中文问题&Stax(Streaming API for XML) (一)

 
       上周周四快速了结了对于搜索引擎的集成以后,又从新回到对ISV WebService接口集成和测试的支持中。测试部发现了一个很棘手的问题,将WS-Security集成到了ASF(应用服务框架)中以后,接口中如果出现中文,就会导致异常抛出。这个问题相关的同事已经跟踪了1,2天了,但是还是没有头绪,离周末还有一天,我赶紧接手,希望能够赶在测试部下周整体测试前修复这个问题。其实前面做了那么多工作,如果一旦这个问题被卡住,那么就会前功尽弃了。
       首先工作就是要确定,究竟是加了WS-Security导致中文问题,还是本来WS的中文返回就有问题。简单的做了单元测试验证了一下,确认了的却是增加了WS-Security导致的中文作为参数或者作为返回值都回抛出异常。根据异常的翻译来看,就是因为在消息体中出现了非法字符。前几天一位同事让我帮忙看WS的一个中文问题时发现,在Http头上对方返回的编码方式是utf-8而在SOAP消息体中,XML的编码方式却写着gbk,所以客户端解析器在解析SOAP消息中的xml时候采用的是Utf-8的编码方式,解析出来的中文自然是不对的。同时翻阅了一下资料,在xml  1.0的内部二进制嵌入必须用base64编码一下,否则是不允许出现非法字符,在xml 1.1已经对这部分作了扩展。所以这次集成了WS-Security产生的问题,可能就会因为这两种原因造成的。
       但是事实上并不是这两方面的原因造成,Axis2和当前很多Web Service框架都采用了Stax方式的Jaxp(Java API for xml processing),在带WS-Security和不带的两种流程中,所用的Jaxp的读写解析器采用的是不同的解析器,所以才会出现了上面的问题,因此还是要从根本上去了解Stax模式的Jaxp框架结构及工作模式。
 
Stax(Streaming API for XML)
背景
Stax不是很新的概念了,在2002年就被提出,在2004年被JCP作为编号为173的JSR正式发布。因此在我们日常开发中如果说到Jsr 173就是关于Streaming API for XML的内容,同时,在lib中如果列了jsr-173.jar或者stax-api.jar也就是对于Streaming API for XML的接口定义包,同时这个包内只是定义框架接口,并没有具体的实现,JSR 173是接口定义规范,各个开源组织或者厂商都可以根据规范实现自身的Stax,这个后面的结构介绍中就会提到。Stax的创始者是BEA的两位系统工程师,所以在我们日后的出错中,如果类似于com.bea.xml.stream.XXX  Class not found 等错误,多半是在所有的lib库中没有对应的Stax的具体实现,只有接口定义。当前支持JSR的实现有Sun,Bea,Oracle,Breeze Factor和其他的一些开源项目(最出名的就是codehaus的woodstox)。
在Jdk 1.6种已经把Stax集成到了内部(javax.xml.transform.stax),顺便说一句的就是,在jdk1.5中,范型和对于Collection的增强是很成功的,而在jdk1.6中虽然没有1.5的很多新特性的融入,但是仔细观察一下就可以发现,其实对于xml和web service的处理和支持作了不少的增强,其实也是针对当前SOA的大趋势作的技术方面的增强,很多概念和实现其实很早就在我们的应用开发中得到体现,个人觉得这也是Sun在开源后的最大受益之处(利用开源来汇集更多的亮点和精华),包括对于1.7的OSGI的畅想,其实都是大势所趋。这让我想起了昨天看程序员增刊第一部分对于Web2.0中的特质的一项描述,利用集体智慧,有所放弃有所收获,放弃了独享的知识专利(当然核心部分可以保留),获得的是广泛的集体参与所带来的智慧亮点。
 
Stax结构体系和功能描述
自Stax的提出开始,其本身就只是一个框架性的规范,并没有具体的实现约束,这也为各个开发商和开源组织认可这个规范提供了一个最基本的优势条件。这点也是当前所有的有生命力的框架或者系统所具备的最基本的特点之一,开放性,制定接口,规范流程,但是不约束具体的实现。
 
功能描述:
       这是我第一次去看JSR的描述,JSR是Java Specification Request的缩写,也就是规范申请,其中所需要填的描述中就详细的写出了申请为JSR的目的(这比类似于国内申请专利之类的,不过感觉更为简洁和开放)。
       Streaming API for XML 描述的是一种基于java用pull方式来处理XML的API。Streaming API通过暴露简单的Iterator模式API提供给开发者处理XML的控制权。同时当前两种关于XML的规范,JAXB和JAX-RPC也十分需要通过Stax模式来处理xml。
       其实早在Stax出现之前,jdk中的已经有了jaxp家族,sax和dom,这两种API分别针对不同的应用场景作了很好的封装。SAX是用于处理XML的事件驱动方法,由很多的回调函数组成。而DOM则是将XML解析成为内存中的树状结构,然后通过API来对XML中的元素和标签进行分析。SAX速度快,需要的内存小,但是无法修改XML,而DOM可以提供对于XML任意节点的访问,同时也可以写入内容到XML,但是缺陷就是速度慢,消耗内存大,需要把XML全部解析完以后才能够继续操作。
       网上对于Stax的好处有很多很详细的文档,就我自己的学习理解来看,比较重要的几点就是:1.pull方式替代了push。Stax从名字上就可以看出和SAX十分相像,其实很大的一点不同就是在于Pull替代了Push。Sax可以实现很多固定的回调函数,然后在执行XML解析的过程中不断的被调用和处理,但是缺点很明显,首先被动回调导致开发者无法根据场景来动态选择如何裁减事件处理需求,同时无法同时处理多个XML。2.Stax比SAX可以更灵活定制事件处理条件。3.Stax可以写入XML。4.Stax除了和SAX提供了一样的API模式的处理方式,还封装了Event模式的对象处理方式。5.Stax比DOM性能高,应用场景广泛,特别是当前很多应用处理xml数据流时都需要边读边分析,当流结束以后就自动关闭了,此时可能已经将流释放,然而此时在作DOM分析已经无法实现,而Stax正好满足了这种需求。因此对于Stax适用范围的描述如下:需要清晰,有效的pull-parsing模式分析XML,另一方面也需要灵活的对XML Stream进行读写操作,需要创建新的事件类型和扩展XML的文档类型以及属性的情况。
 
Stax 体系结构:
       下图中是Stax接口部分的类图,基本上已经包括了Stax规范中的大部分接口定义。
 
WS-Security 中文问题&Stax(Streaming API for XML) (一)_第1张图片
图 Stax接口类图
 
 
两类API 设计接口:Cursor API ,Iterator API
       Cursor API的两个接口定义为:XMLStreamReader和XMLStreamWriter。这部分接口提供了类似于游标方式的方法定义,能够在XML解析过程中,从XML文档流获取或者写入信息,同样也类似于游标读取信息一样,只能前进不能后退,在任意一个时刻能够返回XML中的部分信息片断。
       Iterator API的两个接口定义为:XMLEventReader和XMLEventWriter。Iterator API将XML输入流看作了一组离散的事件对象,这些XML流读入并被Parser分析,然后被解析成为这类事件对象,在开发者的应用程序中,可以主动的Pull(拉)出需要处理的事件对象。
 
对于这两种API的选择基于下面几点:
1.内存有限类似于J2ME可以选择使用cursor API。
2.性能是第一优先级,创建底层的库或者框架结构时使用cursor API更有效。
3.如果需要类似于管道处理XML,使用Iterator API。
4.如果想要修改事件流,使用Iterator API。
5.如果需要应用能够处理可插入的处理流程,使用Iterator API。
6.总的来说,如果你对性能要求不是很高,建议使用Iterator API,因为它更灵活和易扩展。
 
工厂类
Stax采用的是抽象工厂模式来动态的根据环境配置加载不同的Stax的实现。在我原先查找问题的时候看来也是产生WS-Security中文问题的根源,当带WS-Security的时候对于XML流分析和读写采用了codehaus的woodstox包中针对Stax的Cursor API实现,而不带WS-Security时对于XML流分析和读写采用的是axis2中实现的Cursor API。 
工厂类都是抽象类,因此都需要实例来继承实现,如何选取工厂类的实现,并且通过工厂类来生成两套API的实现,按照以下的规则来载入:(以XMLInputFactory为例)
1.       读取系统属性,看配置中是否有javax.xml.Stream.XMLInputFactory等配置的描述。
2.       读取Jre的lib/xml.stream.properties文件来读取配置。
3.       从可读取的Jar中读取在META-INF/services/javax.xml.stream.XMLInputFactory文件来判断载入哪一个的工厂类实现。
4.       使用默认的XMLInputFactory实例。
 
其他接口的说明
       XMLResolver接口可以在分析XML的过程中对于某些资源解析定位到定义和实现的方法上。
       XMLReporter接口用于报告所有的非致命的错误,致命错误通过XMLStreamException来报告。
 
对于接口使用细节可以参看sun公司的webservice tutorial。
 

你可能感兴趣的:(设计模式,xml,框架,webservice,Security)