您的位置:首页 > 其它

构建SOA组合业务服务

2008-08-07 11:57 405 查看
  本文是一
个考虑开发组合应用程序的系列的一部分。组合应用程序集成现有的SOA服务并创建能够以不同的方式组合的新服务。我们最初使用WebSphere
Application Developer IE v5.1开发了一个演示组合应用程序,其中使用了WebSphere Business
Integration SF作为其运行时。随着WebSphere Process Server v6及其对应的开发工具WebSphere
Integration Developer
v6的发布,一种基于服务组件体系结构(SCA)的新编程模型出现了,从而要求将构件从遗留编程模型迁移到新的编程模型。下面我们将与您分享在此迁移过程
期间学习到的一些重要教训。

  本文是一个考虑开发组合应用程序的系列的一部分。组合应用程序集成现有的SOA服务并创建能够以不同的方式组合的新服务。我们最初使用WebSphere Application Developer IE
v5.1开发了一个演示组合应用程序,其中使用了WebSphere Business Integration
SF作为其运行时(请参见本系列的第1部分)。随着WebSphere Process Server v6及其对应的开发工具WebSphere
Integration Developer v6的发布,一种基于服务组件体系结构(Service Component Architecture,SCA)的新编程模型出现了,从而要求将构件从遗留编程模型迁移到新的编程模型。下面我们将与您分享在此迁移过程期间学习到的一些重要教训。
  引言[/b]
  本文描述将原型组合应用程序从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信息中心。
  绑定的迁移问题[/b]
  本系列中的第一篇文章确定了一些由一家银行客户发起的用例。“贷款申请”用例调用了一个BPEL业务流程。该业务流程完成一系列调用服务来处理贷款的步骤。所调用的有些服务使用了Java或EJB绑定。
  Java绑定问题[/b]
  WebSphere Integration Developer v6不支持WebSphere Application
Developer-IE所生成的WSDL中使用的原始Java绑定类型。服务/端口定义使用了某种Java类型。因此在WSDL中生成了一个Java
ClassName而不是一个端点地址。(请参见清单1)。
  清单1. 带Java绑定的WSDL
  name="LoanTrackingServiceProxyPortTypeJavaPort">
  如果将此类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  
name="LoanTrackingServiceEJBPort">
  jndiName="ejb/loantrackingservice/LoanTrackingServiceHome"/>
  这也会由于前面提到的相同原因而在执行期间导致异常(请参见图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代码  

type="s:int" />    name="varString" type="s:string" />
  name="varFloat" type="s:float" />
  SampleElements.xsd
  xmlns:tns="http://sample/elements">
  清单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"));
  }
避免使用重复命名空间
[/b]  在WebSphere Integration Developer中,您不能导入两个带有相同命名空间的不同WSDL文件。当在完全相同的命名空间中声明了复杂类型(在WSDL或XSD中)时,则不能通过迁移向导过程来正确迁移它们。在IBM WebSphere Process Server v6中,具有相同名称和目标命名空间的两个不同WSDL/XSD定义是不允许的。
  清单6和7显示了两个具有相同命名空间的WSDL定义。
  清单6. LoanRequest1.WSDL
  targetNamespace="http://loanrequest/LoanRequest">
  清单7. LoanRequest2.WSDL
  targetNamespace="http://loanrequest/LoanRequest">
  解决方案
  ·更该命名空间以使它们成为唯一的。
  ·验证命名空间更改没有导致副作用。清除工作区并重新构建所有项目。如果没有在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中的一个限制。
  解决方案[/b]
  SCA编程模型可以使用WebSphere Integration Developer/WebSphere Process
Server“选择器”机制在运行时动态更改端点。选择器是WebSphere Integration Developer/WebSphere
Process
Server支持的一种SCA组件,可用于将来自客户端应用程序的操作路由到多个可能的SCA服务实现之一。因此,从功能的角度看,它可以完成与通过
BPE API来动态设置端点相同的事情。图5显示了带有选择器的组装关系图
  


  图5. 使用选择器
  结束语[/b]
  本文描述了在将WebSphere Application Developer-IE业务集成项目迁移到WebSphere
Integration Developer业务集成模块期间遇到的一些问题,并提供了一些解决方案。我们介绍了将Java和EJB绑定替换为SOAP
定的重要性;我们不提倡使用soapenc:Array,并提供了一种与使用soapenc:Array的服务进行交互的方法,用于那些无法更改的服务的
场景(例如,第三方服务)。我们考虑了避免在WSDL定义中使用重复命名空间的重要性和避免使用XSD:anyType定义的原因。最后,我们考虑了使用
选择器来动态更改端点而不是使用BPE API。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: