本文是一个考虑开发组合应用程序的系列的一部分。组合应用程序集成现有的SOA服务并创建能够以不同的方式组合的新服务。我们最初使用WebSphere Application Developer IE v5.1开发了一个演示组合应用程序,其中使用了WebSphere Business Integration SF作为其运行时(请参见本系列的第1部分)。随着WebSphere Process Server v6及其对应的开发工具WebSphere Integration Developer v6的发布,一种基于服务组件体系结构(Service Component Architecture,SCA)的新编程模型出现了,从而要求将构件从遗留编程模型迁移到新的编程模型。下面我们将与您分享在此迁移过程期间学习到的一些重要教训。
引言
本文描述将原型组合应用程序从WebSphere Application Developer-IE v5.1迁移到WebSphere Integration Developer v6的一些问题和解决方案。我们将介绍的主要问题包括WSDL绑定、WSDL接口、XSD定义和业务流程执行语言(Business Process execution Language,BPEL)编码。尽管WebSphere Integration Developer v6具有功能强大的迁移向导,但我们发现可以对简单项目进行自动迁移。然而,更复杂的BPEL应用程序将需要对迁移过程的更深入了解。有关详尽的迁移注意事项,请参考WebSphere Integration Developer帮助或WebSphere Integration Developer/WPS信息中心。
绑定的迁移问题
本系列中的第一篇文章确定了一些由一家银行客户发起的用例。“贷款申请”用例调用了一个BPEL业务流程。该业务流程完成一系列调用服务来处理贷款的步骤。所调用的有些服务使用了Java或EJB绑定。
Java绑定问题
WebSphere Integration Developer v6不支持WebSphere Application Developer-IE所生成的WSDL中使用的原始Java绑定类型。服务/端口定义使用了某种Java类型。因此在WSDL中生成了一个Java ClassName而不是一个端点地址。(请参见清单1)。
清单1. 带Java绑定的WSDL
如果将此类WSDL直接导入SCA模块,那么即使没有异常或由WebSphere Integration Developer标记的错误,所生成的导入也无法成功进行绑定(请参见图1)。事实上,WebSphere Integration Developer V6仅支持带SOAP绑定的Web服务导入。因此,导入的端点将保留为空,从而在将模块部署到WPS并在我们尝试调用它时导致运行时异常。
图1. 带Java绑定的WSDL导入
Enterprise JavaBean(EJB)绑定问题
WebSphere Integration Developer v6不支持WebSphere Application Developer-IE所生成的WSDL中使用的原始EJB绑定类型。其中的服务/端口定义(类似于前面提到的Java类型)使用了EJB类型。因此,提供了EJB Home ClassName和JNDI Name而不是端点地址。(请参见清单2)。
清单2. 带EJB绑定的WSDL
这也会由于前面提到的相同原因而在执行期间导致异常(请参见图2)。
图2. 带EJB绑定的WSDL导入
解决方案
·丢弃带EJB或Java绑定的以前WSDL。
·重新生成带SOAP绑定的对应Web服务,并将其直接导入SCA模块。
·修改BPEL流程以引用新导入的Web服务接口。
WSDL接口的迁移问题
本系列第一部分中讨论过的用例之一是贷款发放场景。在客户申请贷款之后,一名扮演“平台销售(Platform Sales)”角色的银行员工审核贷款请求并批准或拒绝该请求。此用例的部分地方调用了一个信用记录服务。在此服务调用期间,使用document/literal样式并避免RPC样式及其soapenc:Array是非常重要的。但是在需要连接到某个使用该样式的服务的场景中,我们如何做呢?接下来的部分将讨论此问题以及避免使用重复命名空间的重要性。
避免使用soapenc:Array
避免创建或导入引用soapenc:Array类型的WSDL接口,因为SCA编程模型本身并不支持该接口。WPS 6.0将RPC样式的SOAP编码数组类型视为具体类型的无限序列。因此,建议不要使用它们。标准方法是使用document/literal样式。WebSphere Application Developer-IE生成的原始WSDL文件中的soapenc:Array类型定义如清单3所示。
清单3. soapenc:Array的XML类型定义
解决方案1
·更改WSDL中的数组类型定义。
·重新生成Web服务。
·再次运行WebSphere Application Developer-IE Service Project迁移向导,以在WebSphere Integration Developer中生成新构件(服务项目和BEPL流程中修改后的Java代码片段)。
解决方案2
然而,在某些情况下,SCA应用程序必须调用某个使用soapenc:Arraytype的外部服务。(例如,调用某个外部信用记录服务,该服务在其接口定义中使用了soapenc:Array类型)。在这种情况下,修改服务实现和接口定义是不可能的,因此必须使用其他解决方案来解决此问题。
·通过添加占位符元素来人工更改导入的外部WSDL,这些元素可以在将该WSDL导入SCA模块后促进后续的迁移工作。
·使用服务数据对象(Service Data Object,SDO)API来处理SCA模块中的Java代码片段中的soapenc:Array数据。
清单4是一个示例,其中的数据对象根类型为soapenc:Array。请注意sampleElements DataObject是如何通过所列出的第二个模式来创建的。首先获得该DataObject的类型,然后再获得sampleStructElement的属性(请参见清单5)。这实际上是一个占位符属性,并且仅用于获得一个有效的属性来将DataObjects添加到该序列。
清单4. 示例WSDL代码
SampleElements.xsd
清单5. 该Web服务的示例客户端代码
// create the input DataObject and get the SDO sequence for the any element
DataFactory dataFactory=DataFactory.INSTANCE;
DataObject arrayOfStruct = dataFactory.create(
“http://soapinterop.org/xsd”,”ArrayOfSOAPStruct”);
Sequence sequence=arrayOfStruct.getSequence(“any”);
// Get the SDO property for sample element we want to use here to populate the sequence
// We have defined this element in an XSD file, see SampleElements.xsd
DataObject sampleElements=dataFactory.create(“http://sample/elements”, “DocumentRoot”);
Property property = sampleElements.getType().getProperty(“sampleStructElement”);
//Add the elements to the sequence
DataObject item=dataFactory.create(“http://soapinterop.org/xsd”, “SOAPStruct”);
item.setInt(“varInt”, 1);
item.setString(“varString”, “Hello”);
item.setFloat(“varFloat”, 1.0f);
sequence.add(property, item);
item=dataFactory.create(“http://soapinterop.org/xsd”, “SOAPStruct”);
item.setInt(“varInt”, 2);
item.setString(“varString”, “World”);
item.setFloat(“varFloat”, 2.0f);
sequence.add(property, item);
//Invoke the echoStructArray operation
System.out.println(“[client] invoking echoStructArray operation”);
DataObject echoArrayOfStruct =
(DataObject)interopTest.invoke(“echoStructArray”, arrayOfStruct);
// Display the results
if (echoArrayOfStruct!=null)
{
sequence=echoArrayOfStruct.getSequence(“any”);
for (int i=0, n=sequence.size(); i
item=(DataObject)sequence.getValue(i);
// create the input DataObject and get the SDO sequence for the any element
DataFactory dataFactory=DataFactory.INSTANCE;
DataObject arrayOfStruct =
dataFactory.create (“http://soapinterop.org/xsd”,”ArrayOfSOAPStruct”);
Sequence sequence=arrayOfStruct.getSequence(“any”);
// Get the SDO property for sample element we want to use here to populate the sequence
// We have defined this element in an XSD file, see SampleElements.xsd
DataObject sampleElements=dataFactory.create(“http://sample/elements”,
“DocumentRoot”);
Property property = sampleElements.getType().getProperty(“sampleStructElement”);
//Add the elements to the sequence
DataObject item=dataFactory.create(“http://soapinterop.org/xsd”, “SOAPStruct”);
item.setInt(“varInt”, 1);
item.setString(“varString”, “Hello”);
item.setFloat(“varFloat”, 1.0f);
System.out.println(“[client] item varInt = “+ item.getInt(“varInt”)+”
varString=”+item.getString(“varString”)+” varFloat=”+item.getFloat(“varFloat”));
}
避免使用重复命名空间
在WebSphere Integration Developer中,您不能导入两个带有相同命名空间的不同WSDL文件。当在完全相同的命名空间中声明了复杂类型(在WSDL或XSD中)时,则不能通过迁移向导过程来正确迁移它们。在IBM WebSphere Process Server v6中,具有相同名称和目标命名空间的两个不同WSDL/XSD定义是不允许的。
清单6和7显示了两个具有相同命名空间的WSDL定义。
清单6. LoanRequest1.WSDL
清单7. LoanRequest2.WSDL
解决方案
·更该命名空间以使它们成为唯一的。
·验证命名空间更改没有导致副作用。清除工作区并重新构建所有项目。如果没有在WebSphere Integration Developer中检测到任何错误,则将更新后的SCA应用程序部署到WebSphere Process Server中并进行测试。
对于从EJB生成的任何WSDL和XSD,我们应该确保目标命名空间是唯一的(Java类名称和包名称用于创建目标命名空间),以避免在迁移到WebSphere Process Server V6时发生冲突。
XSD迁移问题
在前面提到的与贷款发放有关的同一个用例中,我们使用了返回类型Object,此类型生成一个anyType类型,然而后者却具有下一部分所描述的后果。
避免使用xsd:anyType
准确定义WSDL接口。避免使用引用xsd:anyType的XSD complexType,因为WebSphere Integration Developer v6不支持该类型。在尝试设置该类型的值时将会导致错误。
在下面的示例中,导入SCA模块的WSDL有一个指定了anyType的complexType,从而在操作的输出中导致了类型anyType(请参见图3)。虽然在开发期间没有在WebSphere Integration Developer中检测到异常或错误,但是在运行时期间,当尝试获取或设置Java代码片段中的业务对象数据项的值时,将会引发一个“类强制转换异常”。
图3. 带xsd:anyType的XML类型定义
例如,在尝试使用一个Boolean值来设置Java代码片段中的getVariableReturn时,将会导致从WebSphere Process Server运行时中引发类强制转换异常。
图4. anyType导致的类强制转换异常
//将存在一个由类型为anyType的value项导致的类强制转换错误; setDecisionVar.set(“getVariableReturn”,(Object)(new Boolean(true));
解决方案
·修改对应的会话Bean接口,以避免使用Object作为输入/输出参数类型。(通过将参数类型指定为Object,所生成的WSDL将指定xsd:anyType作为对应的XML元素类型。)
·重新生成Web服务,随后可将其导入SCA模块。
·按照新的WSDL修改迁移后的BPEL流程中的所有相关调用点。
BPEL迁移问题
本系列第一部分中使用的贷款发放用例使用一个信用记录服务来批准或拒绝贷款。其中存在动态设置该服务端点的要求。该端点最初是使用业务流程引擎(Business Process Engine,BPE)API来设置的。然而,WebSphere Integration Developer /WebSphere Process Server具有一种更好的机制可供使用。
动态设置端点(第一个问题)
WebSphere Application Developer-IE可以使用BPEL流程中嵌入的Java代码片段来动态设置端点。然而,该代码不再有效,因为WebSphere Process Server中的BPE API已经更改。因此,需要更新代码以使用新的API。用于动态设置端点的原始代码如清单8所示。在清单9中,该代码已迁移为使用新的WebSphere Process Server BPE API。
清单8. WebSphere Application Developer-IE中的动态端点设置代码
String ep = getApproveCheckRequest().getApprovalExtensionEP();
com.ibm.websphere.srm.bpel.wsaddressing.AttributedURI address = new AttributedURI();
com.ibm.ws.webservices.engine.types.URI addressValue = new URI(ep);
com.ibm.websphere.srm.bpel.wsaddressing.EndpointReferenceType
e = new EndpointReferenceType();
address.setValue(addressValue);
e.setAddress(address);
this.setPartnerLinkLoanApprovalExtension(e);
清单9. WebSphere Integration Developer中的动态端点设置代码
//Get the new address of approvalExtension parnter
String ep = approveCheckRequest.getString(“approvalExtensionEP”);
System.out.println(“Setting approval extension endpoint to: ” + ep);
if (ep != null && ep.length() > 0) {
ServiceManager sm = ServiceManager.INSTANCE;
Service s = (Service)sm.locateService(“LoanApprovalExtension”);
EndpointReference endPoint = s.getEndpointReference();
//update the endpoint address for the partner “LoanApprovalExtension”
endPoint.setAddress(ep);
}
尽管用于设置引用伙伴端点的代码已经更新,但是如果该伙伴已连接到某个组件(如果在运行时期间在动态重置之前向它分配了绑定),则端点更改将不会生效。在运行时期间,调用仍将定向到缺省端点。
动态设置端点(第二个问题)
当将SCA模块中的某个引用保留为空时(例如,它未连接到任何SCA组件),则可以使用上述动态端点设置代码来将绑定信息附加到该空引用。然而,如果我们尝试使用不同的端点绑定来再次更新其端点,则该引用将不再有效,并且会引发一个“文档根目录错误”异常。这是WebSphere Process Server v6中的一个限制。
解决方案
SCA编程模型可以使用WebSphere Integration Developer/WebSphere Process Server“选择器”机制在运行时动态更改端点。选择器是WebSphere Integration Developer/WebSphere Process Server支持的一种SCA组件,可用于将来自客户端应用程序的操作路由到多个可能的SCA服务实现之一。因此,从功能的角度看,它可以完成与通过BPE API来动态设置端点相同的事情。图5显示了带有选择器的组装关系图
图5. 使用选择器
结束语
本文描述了在将WebSphere Application Developer-IE业务集成项目迁移到WebSphere Integration Developer业务集成模块期间遇到的一些问题,并提供了一些解决方案。我们介绍了将Java和EJB绑定替换为SOAP绑定的重要性;我们不提倡使用soapenc:Array,并提供了一种与使用soapenc:Array的服务进行交互的方法,用于那些无法更改的服务的场景(例如,第三方服务)。我们考虑了避免在WSDL定义中使用重复命名空间的重要性和避免使用XSD:anyType定义的原因。最后,我们考虑了使用选择器来动态更改端点而不是使用BPE API。
作者简介
Javier Garcia是一位拥有20多年开发经验的顾问软件工程师。他当前在SWG Strategy and Technology部门工作,工作重点是SOA和组合应用程序。
Qiang Wang是China Technology Institute, China Software Development Laboratory的一位软件工程师。他的工作重点是IBM Incubator Project和SOA相关主题。他的兴趣包括J2EE、SOA、MDA/MDD、AOP和RUP。他当前从事与WBM、WebSphere Integration Developer和WPS相关的开发工作。
我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。
我原创,你原创,我们的内容世界才会更加精彩!
【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】
微信公众号
TechTarget
官方微博
TechTarget中国
相关推荐
-
保险公司如何能从BPEL中获益
对于保险业整合不同系统是一件寻常的工作。但保险公司经常会面临监管条例改变和应对不同的顾客需求。为了解决这些系统问题,软件专家正在使用一种强大的工具——BPEL。
-
2013年业务流程执行语言(BPEL)现状
在SOA领域中,BPEL拥有属于自己的集成系统和自动化工作流,为协调完全异构系统而提供一致的流程。
-
如何开发BPEL复合应用
大多数软件架构师对应用的组件化、SOA和工作流或者服务总线流程非常熟悉,也对组合应用如何将这些基本元素结合在一起非常熟知。
-
如何在SOA中执行BPEL测试?
几乎所有面向服务架构(SOA)用户都在使用业务流程执行语言(BPEL)。作为编排粗粒度的业务流程流工具,BPEL实际上是行业的标准,但是还是会引起测试问题。