天天看點

Web服務模組化(一):XML模式

        這篇文章是探讨 UML 模組化(特别是使用IBM Rational Software Architect)在标準化 Web 服務的細節設計模型方面的使用的系列的第一部分,該系列共有三個部分。着重于軟體服務的模組化,而本系列描述了Web 服務模型的細節,如何做出具體技術決定,如果獲得和XML 模式以及WSDL (Web 服務定義語言)對應的工件,等等。本文将重點介紹模組化和産生XML 模式。

序言

這一系列的文章較長的描述 了如何建立Web 服務相關的結構模型,以及您可以如何使用IBM®Rational®Software Architect (RSA)在實際應用中實作這些模型。系列中的文章将使用實際的例子說明如何使用RSA以一種簡單和可維護的方式捕捉 Web 服務的設計,并同時捕捉到最終工件需要的大部分外在細節。

本系列探讨了以下主題:

  • 第一部分——模組化和産生 XML 模式。
  • 第二部分——模組化和産生 WSDL。
  • 第三部分——将模式應用到 Web 服務工件的産生中。

您 将從了解 XML 模式開始;這是因為,首先,單獨使用WSDL要求資訊以模式的形式描述,更為重要的是,資訊——實際上所有資料——的設計應該是一個清楚和有效管理的活 動,而不是接口設計的副産品。您在本文中看到的資料結構将作為WSDL資訊的元素在下一篇文章中繼續使用。

為什麼為 Web 服務建立詳細模型?

一 個有趣的問題是,為Web 服務建立詳細的模型是否有價值。畢竟,一個試圖抽象掉不必要的細節以使您用一種在實作級不夠清楚的方式了解系統的模型不是足夠的嗎?顯然,在某些方面答案 是肯定的,您希望提供一個下層實作工件的模型,而這種方法又允許您利用可視化語言的能力來簡單地表達複雜的關系并逐級實作更大資料集合的表達。

這 種為細節設計元素模組化的方法在整體的模型驅動開發(MDD)方法中比較适用,在模型驅動開發方法中您可以定義多個互聯的模型,用它們遞進地表達問題或解決 方案的精确的觀點。這種方法如圖1所示。模型的特定配置是具體到被模型化的服務的,是以不使用通常關聯到對象管理組織(OMG)的模型驅動架構(MDA) 的術語,包括計算無關,平台無關,以及平台相關的模型,等等。

圖1. Web 服務開發的 MDD 配置

Web服務模組化(一):XML模式

對配置元素的描述如下:

  • 分析模型:一個高度抽象的模型,包含了解決方案的代表元素,而不包含任何具體的平台或結構方面的考慮
  • 軟體服務設計模型:一個從分析模型派生出來,應用了面向服務的架構方式的模型,但是不包含實際實作技術和平台
  • Web 服務實作模型:一個從軟體服務設計模型派生出來的模型,Web 服務實作的特定細節被添加和提煉,以保證産生的工件被精确制定
  • XML或WSDL工件:實際可部署的工件,包括XML 模式和WSDL文檔
  • 需求:每個模型的開發中使用的要求,同時還用來配置模型之間的轉換

您會注意到有兩種實作實際工件的方法:直接從軟體服務模型實作或通過Web 服務模型實作。在第一種情況下會進行從更為抽象的軟體服務模型的預設轉換。盡管如此,如果需要對産生的工件的更多控制,那麼可以使用更詳細的Web 服務模型來更精确地定義目标。

Web服務模組化(一):XML模式
Web服務模組化(一):XML模式
Web服務模組化(一):XML模式

模組化 XML 模式

在 XML 模式的模型建立中——見參考資源,[3,4]—— 意識到一些相對“顯而易見”的映射——從UML面向對象的世界觀到XML 模式以文檔為中心——是非常重要的,它們使您能夠從一個簡單的類模型自動産生出模式。不幸的是,這通常不是一個令人滿意的經曆,因為這些預設産生的模式元 素無法與您手工建立的結構類型相比。是以,模型應以這樣一種方式建立:産生的XML 模式能夠被協調以準确的建立設計者的心中所想。

RSA 的 UML 到 XML 模式的轉換

本文中使用的例子是用RSA開發的——見參考資源,[6]。 版本 6.0.1引進了一組新的特性,包括下文介紹的 UML to XML schema 的轉換。UML to XML schema 轉換是RSA釋出的一組模型到模型和模型到文本的轉換之一,而且是用一個開放可擴充性的接口建構的,是以您或者第三方可以自行開發新的轉換。

現在就讓我們進入一個簡單模型的示例,您希望為它建立一個XML 模式。為了完成任務,您将需要一張來自 XML 模式入門本身提供的購買訂單表格(資源,[5]),如圖2所示。

圖2. 初始購買訂單模型

Web服務模組化(一):XML模式

右鍵點選包含購買訂單元素的包來運作 UML to XSD 轉換——在圖上或模型浏覽器中點選都可以。點選Transform > Run Transformation > UML to XSD,如圖3所示。當您選擇了一個轉換,您将看到一個對話框,在這裡您可以輸入額外的轉換選項。如果您是第一次運作轉換,務必把包含您的模型的Eclipse項目設定為轉換的目标。

圖3. RSA 的 Transformation 菜單

Web服務模組化(一):XML模式

為模型産生的模式與清單1近似。注意轉換将産生一個警告,因為模型沒有指定目标命名空間,而這是模式的一個要求。

清單1. 産生的購買訂單模式

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <xsd:complexType name="purchaseOrder">
    <xsd:sequence>
      <xsd:element name="orderDate"/>
      <xsd:element name="shipTo" type="USAddress"/>
      <xsd:element name="billTo" type="USAddress"/>
      <xsd:element minOccurs="0" name="comment" type="string"/>
      <xsd:element name="items" type="Items"/>
    </xsd:sequence>
  </xsd:complexType>
  <xsd:complexType name="Items">
    <xsd:sequence>
      <xsd:element maxOccurs="unbounded" minOccurs="0" name="item" type="Item"/>
    </xsd:sequence>
  </xsd:complexType>
  <xsd:complexType name="USAddress">
    <xsd:sequence>
      <xsd:element name="name" type="string"/>
      <xsd:element name="city" type="string"/>
      <xsd:element name="state" type="string"/>
      <xsd:element name="zip" type="string"/>
      <xsd:element name="country" type="string"/>
    </xsd:sequence>
  </xsd:complexType>
  <xsd:complexType name="Item">
    <xsd:sequence>
      <xsd:element name="productName" type="xsd:string"/>
      <xsd:element name="quantity" type="xsd:positiveInteger"/>
      <xsd:element name="USPrice" type="xsd:decimal"/>
      <xsd:element name="comment" type="string"/>
      <xsd:element name="shipDate" type="xsd:date"/>
      <xsd:element name="partNum" type="SKU"/>
    </xsd:sequence>
  </xsd:complexType>
  <xsd:complexType name="SKU">
    <xsd:complexContent>
      <xsd:extension base="string">
        <xsd:sequence/>
      </xsd:extension>
    </xsd:complexContent>
  </xsd:complexType>
</xsd:schema>
      

讓我們比較産生的模式和入門中手工完成的版本,并探讨一些問題。首先,您需要添加命名空間,它由轉換本身識别。為了完成這項工作您必須把一個UML profile 應用到您的模型中,該 profile 允許您通過使用UML的原型來提供額外資訊,以很好地協調産生過程并捕捉到其它屬性。選擇包含您的模式元素的包以應用 profile 和原型,然後打開屬性視窗和 profile 标簽,如圖4所示。

圖4. 将 profile 應用于您的模型

Web服務模組化(一):XML模式

點選Add profile 并在清單中選擇 XSDProfile。這一操作将加載轉換原型,那麼選擇相同的包并打開 Properties 視窗中的 Stereotypes 标簽。一旦您添加了«schema»原型,滾動原型屬性并向 targetNamespace 和 targetNamespacePrefix 屬性中添加需要的值,如圖5所示。

圖5. «schema» 原型屬性

Web服務模組化(一):XML模式

這些操作将允許轉換産生一個更為完整的XML <schema/>元素。但是在您重新運作轉換之前,再添加一個項。在屬性視窗中打開Documentation 标簽并輸入文本

Purchase order schema for Example.com. Copyright 2000 Example.com. All rights reserved.

。現在,重新運作轉換并檢查産生的模式——現在隻需要看檔案的最前面就可以了——如清單2所示。

清單2. 重新産生的模式

<xsd:schema xmlns:po="http://www.example.com/PO1" 
            xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
            targetNamespace="http://www.example.com/PO1">
  <xsd:annotation>
    <xsd:documentation>Purchase order schema for Example.com.
    Copyright 2000 Example.com. All rights reserved.
    </xsd:documentation>
  </xsd:annotation>
      

正如您看到的,現在您不僅指定了目标的命名空間,而且還建立了一個命名空間值

PO

來限制模式和其中包含的來自示例的注解文檔。

現在,您需要進行第二次變化,因為不是所有圖1中顯示的UML屬性都能成為XML元素,如清單1所 示。您需要其中一些UML屬性作為XML屬性被産生,是以您将再次使用 profile 來告知轉換需要做什麼;在這個例子中,您将需要選擇屬性并添加原型«attribute»,如圖6中所示。在您完成屬性選擇以前,還需要把 USAddress::country的屬性類型改為XML 模式類型 NMTOKEN,并指定預設值

US

。要設定正确的類型,選擇 Country 屬性,打開屬性的General 标簽,并點選Select type。在産生的對話框中,滾動XSDDataTypes模型并選擇需要的類型。

圖6. 在模型中指定XML屬性

Web服務模組化(一):XML模式

但是,現在您又有了一個問題:SKU 類是作為一個複合類型産生的,您無法把它作為一個屬性的類型(如果您回到示例模式中您會看到SKU是一個簡單類型,有其指定的模式)。是以,把原型«simpleType»應用于SKU類,并把原型模式屬性設定為

/d{3}-[A-Z]{2}

。另外,確定SKU類在XSDDataTypes模型中繼承了字元串類,而不是繼承了一個本地字元串類。這樣屬性和簡單類型定義就完成了,如清單3中的片段所示。

清單3:指明變化的代碼片段

...
<xsd:complexType name="USAddress">
    <xsd:sequence>
      <xsd:element name="name" type="xsd:string"/>
      <xsd:element name="street" type="xsd:string"/>
      <xsd:element name="city" type="xsd:string"/>
      <xsd:element name="state" type="xsd:string"/>
      <xsd:element name="zip" type="xsd:string"/>
    </xsd:sequence>
    <xsd:attribute default="US" name="country" type="xsd:NMTOKEN"/>
  </xsd:complexType>
...
  <xsd:simpleType name="SKU">
    <xsd:restriction base="xsd:string">
      <xsd:pattern value="/d{3}-[A-Z]{2}"/>
    </xsd:restriction>
  </xsd:simpleType>
      

正如您所看到的,您與入門中手工的購買訂單模式示例更加接近了,但是還有以下兩個差別:

  • 條目的複合類型中的 Anonymous 類型
  • 對全局元素聲明的需要

先來看一下 Anonymous 類型,您需要向模型元素項中加入原型«complexType»。這看起來是多餘的,因為預設的轉換為模型類型建立了一個複合類型,但是請仔細觀察原型的屬性。為完成這個例子,需要把 Anonymous 屬性的值設為

True

。 您還需要為 Quantity 屬性作相似的工作:您需要建立一個匿名簡單類型。具體做法是,先建立一個新的類并将其命名為 Quantity (在本例中)。然後,在XSDDataTypes模型中建立一個到positiveInteger類的泛化關聯。現在,在 原型化的屬性 Quantity 上,設定

anonymous=True

以及

maxExclusive=100

,然後把 Item::quantity 的類型改為新的 Quantity 類,如圖7所示。

圖7. 指定 Quantity 匿名簡單類型

Web服務模組化(一):XML模式

這些更改的結果是一個對于條目複合類型更為完整的定義,如清單4所示。

清單4:項複合類型定義

<xsd:complexType name="Items">
    <xsd:sequence>
      <xsd:element name="item" minOccurs="0" maxOccurs="unbounded">
        <xsd:complexType>
          <xsd:sequence>
            <xsd:element name="productName" type="xsd:string"/>
            <xsd:element name="quantity">
              <xsd:simpleType>
                <xsd:restriction base="xsd:positiveInteger">
                  <xsd:maxExclusive value="100"/>
                </xsd:restriction>
              </xsd:simpleType>
            </xsd:element>
            <xsd:element name="USPrice"  type="xsd:decimal"/>
            <xsd:element ref="comment"   minOccurs="0"/>
            <xsd:element name="shipDate" type="xsd:date" minOccurs="0"/>
          </xsd:sequence>
          <xsd:attribute name="partNum" type="SKU" use="required"/>
        </xsd:complexType>
      </xsd:element>
    </xsd:sequence>
  </xsd:complexType>
      

最後一個問題是,購買訂單本身在入門中是作為一個全局元素聲明的,屬于全局複合類型。此外,comment 元素也是全局定義為字元串類型的。在模型中定義全局元素聲明比您前面做的在模型中添加一些“标記”要複雜一些。這些變化如圖8所示。

圖8. 全局元素聲明

Web服務模組化(一):XML模式

要實作圖8中的變化,您需要對模型作如下工作:

  • 将 purchaseOrder 重命名為 purchaseOrderType
  • 向 purchaseOrderType 中添加原型«complexType»(不一定是必須的,但是它使模型的意義更為明确)
  • 建立一個名為purchaseOrder 的新類,并加入原型«global»
  • 向 purchaseOrder 中添加一個屬性,名字也是 purchaseOrder,原型是«element»并将類型指定為 purchaseOrderType
  • 建立一個名為 comment的新類,并加入原型«global»
  • 向 comment 中添加一個屬性,名字也是 comment,原型是 «element» 并将類型指定為 XSDDataTypes::string
  • 将 Item::comment 的類型改為建立立的 comment 類
  • 将 Item::comment 的多重性從1改為0..1

所有這些改變的結果如清單5所示:産生的模式與原始例子在意義上是完全相同的,盡管文本的順序可能有所不同。

清單5:現在産生的模式與基本示例的意義是相同的了

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:PO="http://www.example.com/PO1" 
            xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
            targetNamespace="http://www.example.com/PO1">
  <xsd:annotation>
    <xsd:documentation>Purchase order schema for Example.com.
    Copyright 2000 Example.com. All rights reserved.
    </xsd:documentation>
  </xsd:annotation>
  <xsd:complexType name="USAddress">
    <xsd:sequence>
      <xsd:element name="name" type="xsd:string"/>
      <xsd:element name="street" type="xsd:string"/>
      <xsd:element name="city" type="xsd:string"/>
      <xsd:element name="state" type="xsd:string"/>
      <xsd:element name="zip" type="xsd:string"/>
    </xsd:sequence>
    <xsd:attribute default="US" name="country" type="xsd:NMTOKEN"/>
  </xsd:complexType>
  <xsd:simpleType name="SKU">
    <xsd:restriction base="xsd:string">
      <xsd:pattern value="/d{3}-[A-Z]{2}"/>
    </xsd:restriction>
  </xsd:simpleType>
  <xsd:element name="purchaseOrder" type="PO:purchaseOrderType"/>
  <xsd:element name="element" type="xsd:string"/>
  <xsd:complexType name="purchaseOrderType">
    <xsd:sequence>
      <xsd:element name="shipTo" type="PO:USAddress"/>
      <xsd:element name="billTo" type="PO:USAddress"/>
      <xsd:element name="items" type="PO:Items"/>
    </xsd:sequence>
    <xsd:attribute name="orderDate" type="xsd:date"/>
  </xsd:complexType>
  <xsd:complexType name="Items">
    <xsd:sequence>
      <xsd:element maxOccurs="unbounded" minOccurs="0" name="item">
        <xsd:complexType>
          <xsd:sequence>
            <xsd:element name="productName" type="xsd:string"/>
            <xsd:element name="quantity">
              <xsd:simpleType>
                <xsd:restriction base="xsd:positiveInteger">
                  <xsd:maxExclusive value="100"/>
                </xsd:restriction>
              </xsd:simpleType>
            </xsd:element>
            <xsd:element name="USPrice" type="xsd:date"/>
            <xsd:element minOccurs="0" ref="PO:element"/>
            <xsd:element name="shipDate" type="xsd:date"/>
          </xsd:sequence>
          <xsd:attribute name="partNum" type="PO:SKU"/>
        </xsd:complexType>
      </xsd:element>
    </xsd:sequence>
  </xsd:complexType>
</xsd:schema>
      
Web服務模組化(一):XML模式
Web服務模組化(一):XML模式
Web服務模組化(一):XML模式

一個更完整的例子

作 為 使用 IBM 軟體 Rational 産品 項目的一部分,我們開發了一個模型庫,其中包含了很多 Web 服務家族的規範(通常稱為WS-*)的表達。圖9顯示了目前已建立了模型的标準集合,同時也顯示了使用UML «packageimport»關系能夠指明模式間的依賴性。特别地,這些UML關系将産生XML 模式導入聲明,使我們能夠簡單友善地為具體領域的模式建立模型,并把它們作為一組相關模式元件。

圖9. WS-* 模式和依賴性

Web服務模組化(一):XML模式

如 果您把 WS-Addressing 模式作為這些模式中普遍出現的結構的代表來加以研究的話,您會發現它包含了一些從簡單類型中派生出來的複合類型(我們在前面購買訂單的例子中看到了簡單類 型的衍生)。其中兩個複合類型還增加了額外屬性:ServiceNameType::portName 和 Relationship::RelationshipType。更為有趣的是,所有四個新的複合類型都允許通配符屬性,如圖10所示。通過允許作者向标 準類型中添加額外的屬性來引進未來的擴充,這是 XML 模式的一個能力。要實作這一特性,使用«wildcard»和«attribute»原型的結合(現在屬性名無關緊要了,但是按正常我們使用任何或任何屬性)。

圖10. 從 XSD 類型衍生出的複合類型

Web服務模組化(一):XML模式

接 下來,觀察模式引進的新複合類型。再次注意到 EndpointReferenceType 類型不僅允許通配符屬性,還允許通配符元素(使用«wildcard»和«element»原型的組合)。您還會看到我們用 UML 多重性[0..1]将三個屬性置為可選的,如圖11所示。

圖11. WS-Addressing 複合類型

Web服務模組化(一):XML模式

最後,WS-Addressing 揭示了一組全局元素聲明,标準期望使用者複用這些聲明。它們在圖12中有所表示。

圖12. 可複用元素聲明

Web服務模組化(一):XML模式

按上述步驟運作 UML to XSD 轉換的結果如清單6所示。再一次地,我們可以将這一結果與W3C的标準模式進行比較。

清單6:從 UML to XSD 轉換得到的結果模式

<?xml version="1.0"?>
<xs:schema targetNamespace="http://schemas.xmlsoap.org/ws/2003/03/addressing" 
           xmlns:wsa="http://schemas.xmlsoap.org/ws/2003/03/addressing" 
           xmlns:xs="http://www.w3.org/2001/XMLSchema" 
           elementFormDefault="qualified" 
           blockDefault="#all">
  <xs:element name="EndpointReference" type="wsa:EndpointReferenceType"/>
  <xs:complexType name="EndpointReferenceType">
    <xs:sequence>
      <xs:element name="Address" type="wsa:AttributedURI"/>
      <xs:element name="ReferenceProperties" 
			         type="wsa:ReferencePropertiesType" minOccurs="0"/>
      <xs:element name="PortType" type="wsa:AttributedQName" minOccurs="0"/>
      <xs:element name="ServiceName" type="wsa:ServiceNameType" minOccurs="0"/>
      <xs:any namespace="##other" processContents="lax" 
             minOccurs="0" maxOccurs="unbounded">
        <xs:annotation>
          <xs:documentation>
             If "Policy" elements from namespace 
             "http://schemas.xmlsoap.org/ws/2002/12/policy#policy" are used, 
             they must appear first (before any extensibility elements).
          </xs:documentation>
        </xs:annotation>
      </xs:any>			
    </xs:sequence>
    <xs:anyAttribute namespace="##other" processContents="lax"/>
  </xs:complexType>
  <xs:complexType name="ReferencePropertiesType">
    <xs:sequence>
      <xs:any processContents="lax" 
                 minOccurs="0" maxOccurs="unbounded"/>
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="ServiceNameType">
    <xs:simpleContent>
      <xs:extension base="xs:QName">
        <xs:attribute name="PortName" type="xs:NCName"/>
        <xs:anyAttribute namespace="##other" processContents="lax"/>
      </xs:extension>
    </xs:simpleContent>
  </xs:complexType>
  <xs:complexType name="Relationship">
    <xs:simpleContent>
      <xs:extension base="xs:anyURI">
        <xs:attribute name="RelationshipType" 
                         type="xs:QName" use="optional"/>
        <xs:anyAttribute namespace="##other" processContents="lax"/>
      </xs:extension>
    </xs:simpleContent>
  </xs:complexType>
  <xs:complexType name="AttributedQName">
    <xs:simpleContent>
      <xs:extension base="xs:QName">
        <xs:anyAttribute namespace="##other" processContents="lax"/>
      </xs:extension>
    </xs:simpleContent>
  </xs:complexType>
  <xs:complexType name="AttributedURI">
    <xs:simpleContent>
      <xs:extension base="xs:anyURI">
        <xs:anyAttribute namespace="##other" processContents="lax"/>
      </xs:extension>
    </xs:simpleContent>
  </xs:complexType>
  <xs:element name="MessageID" type="wsa:AttributedURI"/>
  <xs:element name="RelatesTo" type="wsa:Relationship"/>
  <xs:element name="To" type="wsa:AttributedURI"/>
  <xs:element name="Action" type="wsa:AttributedURI"/>
  <xs:element name="From" type="wsa:EndpointReferenceType"/>
  <xs:element name="ReplyTo" type="wsa:EndpointReferenceType"/>
  <xs:element name="FaultTo" type="wsa:EndpointReferenceType"/>
  <xs:element name="Recipient" type="wsa:EndpointReferenceType"/>
</xs:schema>
      

希望這個對 RSA 為 XSD 建立模型的能力的簡要介紹能使您獲得具體領域的模式,以及您的模型中的 Web 服務消息。更深一步,它應該為您提供了結合和分解模式的機會,而您使用的方式可能是用目前其它的模式編輯器很難可視化的。

參考資料

學習

  • 您可以參閱本文在 developerWorks 全球網站上的 英文原文。
  • [1]為面向服務解決方案建立模型:Simon Johnston,The Rational Edge,2005。
  • [2]OMG 模型驅動體系架構:對象管理組織,Inc.
  • [3]XML 模式第一部分:結構(第二版):W3C,2004。
  • [4]XML 模式第二部分:資料類型(第二版):W3C,2004。
  • [5]XML 模式第零部分:入門(第二版):W3C,2004。
  • [6]IBM Rational Software Architect 産品資訊頁:IBM。
  • [7]Web Services Addressing Working Group::W3C。
  • [8]IBM Rational Software Architect 資源頁面:可找到技術文檔、文章、教育、下載下傳和 Rational Software Architect 的産品資訊。

獲得産品和技術

  • IBM Rational Software Architect:從 developerWorks 下載下傳試用版本。

讨論

  • 參與論壇讨論。
  • Rational Software Architect、 Software Modeler、 Application Developer 和 Web Developer 論壇:提出關于Rational Software Architect 方面的問題。

關于作者

Web服務模組化(一):XML模式
Web服務模組化(一):XML模式
Simon 是一位在 IBM Rational軟體 SOA 解決方案小組工作的進階技術人員,他的職責是為SOA模組化工具制定政策。Simon 現在承擔着Rational 軟體以及IBM中XML(W3C Schema工作組),Web Services(RosettaNet體系架構小組)和模組化(OMG UML和OCL小組)等領域的标準活動。Simon同時還寫一些關于業務模組化,軟體模組化和SOA方面的文章,他對這些方面将在哪裡以及何時融合很感興趣。