此部分描述SCA组装模型规范V1.0.0--1.6构件之连线(Wire)、使用构件的其它方法,比如把构件作为组件来使用以及使用included 构件等,最后介绍约束类型。
1.6.4 连线(Wire)
构件中的SCA 连线(wire)连接源组件引用(source component references)和目标组件服务(target component services)。
定义一个连线的方式之一是使用target属性配置一个组件引用。reference元素使用解析此引用的服务的wire-target-URI配置。当引用的multiplicity为0..n或1..n时,多个目标服务是有效的。
定义一个连线的另一个方式是使用composite元素的子元素wire。在composite里可以有0或多个wire元素。当用来连接元素的连线分离时,这种定义连线的方法是很用的,这种定义方式将会简化开发或操作行为。举个例子,用来构建域的组件是相对静态的,但是新的或发生改变的应用就是利用这些组件被有规则的创建,这个创建过程是通过使用不同的连接创建新的组装来完成的。部署连线与组件是无关的,所以将会以很少的工作就可以完成连线的创建或修改。
注意,由wire元素指定的连线等价于由reference的target属性指定的连线。一个reference不能混合使用binding元素指定的endpoint和target属性指定的endpoint,这个规则同样也应用于由单独的wire元素指定的连线。
下面的代码片段展示了composite模式,里面有组件的reference元素、构件服务以及wire子元素:
- <?xml version="1.0" encoding="ASCII"?>
- <!-- Wires schema snippet -->
- <composite xmlns="http://www.osoa.org/xmlns/sca/1.0"
- targetNamespace="xs:anyURI"
- name="xs:NCName" local="xs:boolean"? autowire="xs:boolean"?
- constrainingType="QName"?
- requires="list of xs:QName"? policySets="list of xs:QName"?>
-
- ...
-
- <wire source="xs:anyURI" target="xs:anyURI" />*
-
- </composite>
component的reference元素和service的reference元素对于target有一个由下面wire-target-URI值中的一个或多个且由空格分开而组成的列表:
² <component-name>/<service-name>
Ø 这里目标是一个组件的服务。如果目标组件仅仅有一个带有兼容接口的服务,其名字的指定是可选的。
wire元素有下面的属性:
l source(必需):源组件引用的名字。有效的URI模式如下:
² <component-name>/<reference-name>
u 这里源是一个组件的引用。如果源组件只有一个引用,其名字的指定是可选的。
l target(必需):目标组件服务的名字。有效的URI模式如下:
² <component-name>/<service-name>
u 这里目标是一个组件的服务。如果目标组件仅仅有一个带有兼容接口的服务,其名字的指定是可选的。
对于一个作为组件实现使用的构件,连线仅仅可以连接包含在同一个构件(不管哪一个或哪些文件用来描述此构件)的源和目标。连接构件之外的实体(entities)是通过带有连线的构件的服务和引用来完成的,这些连线在更高层的构件中定义。
一个连线仅仅可以连接一个源到一个目标,如果这个目标实现了一个接口,这个接口要与源所需的接口兼容。源和目标是兼容的,如果满足下列条件:
1. 源接口和目标接口必须都是远程的或本地的。
2. 目标接口的操作必须与源指定的接口里的操作相同或是其超集。
3. 单个操作的兼容性定义为签名(signature)的兼容性,也就是,操作名称、输入类型和输出类型必须一样。
4. 输入和输出类型的顺序也必须一样的。
5. 源期望的错误(Fault)和异常(Exceptions)组成的集合要与目标指定的一样或是其超集。
6. 两个接口中指定的其它属性也要匹配,包括范围(Scope)和回调接口。
一个连线可以在任何一个方向连接不同语言定义的接口(如Java接口与WSDL portType),只要两个接口定义的操作是等价的。操作是等价的是指操作、参数、返回值和错误/异常可以相互对应。
服务客户机(Service clients)不能在运行时请求服务实现提供的额外接口(如Java里“instance of”的结果是不方便的(portable))。一个SCA实现对所有的连线都拥有代理,因此,一个传递到实现的引用对象仅仅拥有此引用的业务接口,而不会是一个用来实现目标服务的Java类实例,甚至这个接口是本地的且目标服务运行在同一个进程里。
注意:部署一个有引用但是没有连线的构件是被允许的。对于一个multiplicity为1..1或1..n的无连线(non-wired)引用来说,SCA运行时提供的部署过程应该会声明一个警告。
1.6.4.1 连线举例(Wire Examples)
图11展示了MyValueComposite2构件的组装图,里面包含服务、组件和引用的连线。

图11. 展示连线的MyValueComposite2构件
下面的代码片段展示了MyValueComposite2的MyValueComposite2.composite文件,这个构件包含了被配置的组件和服务引用。MyValueService服务连接到MyValueServiceComponent。MyValueServiceComponent的customerService引用连接到此构件的CustomerService引用。MyValueServiceComponent的stockQuoteService引用连接到StockQuoteMediatorComponent,而StockQuoteMediatorComponent有一个连接到此构件的StockQuoteService引用。
- <?xml version="1.0" encoding="ASCII"?>
- <!-- MyValueComposite Wires examples -->
- <composite xmlns="http://www.osoa.org/xmlns/sca/1.0"
- targetNamespace="http://foo.com"
- name="MyValueComposite2" >
-
- <service name="MyValueService" promote="MyValueServiceComponent">
- <interface.java interface="services.myvalue.MyValueService"/>
- <binding.ws port="http://www.myvalue.org/MyValueService#
- wsdl.endpoint(MyValueService/MyValueServiceSOAP)"/>
- </service>
-
- <component name="MyValueServiceComponent">
- <implementation.java class="services.myvalue.MyValueServiceImpl"/>
- <property name="currency">EURO</property>
- <service name="MyValueService"/>
- <reference name="customerService"/>
- <reference name="stockQuoteService"
- target="StockQuoteMediatorComponent"/>
- </component>
-
- <component name="StockQuoteMediatorComponent">
- <implementation.java class="services.myvalue.SQMediatorImpl"/>
- <property name="currency">EURO</property>
- <reference name="stockQuoteService"/>
- </component>
-
- <reference name="CustomerService"
- promote="MyValueServiceComponent/customerService">
- <interface.java interface="services.customer.CustomerService"/>
- <binding.sca/>
- </reference>
-
- <reference name="StockQuoteService" promote="StockQuoteMediatorComponent">
- <interface.java interface="services.stockquote.StockQuoteService"/>
- <binding.ws port="http://www.stockquote.org/StockQuoteService#
- wsdl.endpoint(StockQuoteService/StockQuoteServiceSOAP)"/>
- </reference>
-
- </composite>
1.6.4.2 自动连线(Autowire)
SCA提供一个叫Autowire的特征,它能帮助简化构件的组装。自动连线能让组件引用自动地连接满足这些引用的组件服务,而不需要在引用和服务之间创建显式的连线。当使用autowire时,一个没有被提升的、在构件里没有显式与服务连线的组件引用会自动连接同一个构件里的目标服务。自动连线是通过在构件中寻找匹配引用接口的服务接口来完成的。
autowire不是默认使用的。通过设置autowire属性为true,自动连线就可以使用了。autowire为false时,自动连线无效。autowire属性可以应用于下面的任何一个构件里的元素:
l reference
l component
l composite
当一个元素没有为autowire属性显示设定值时,它会继承其父元素的设置。也就是说,一个reference元素会从包含它的组件来继承设置。一个component元素会从包含它的构件继承设置。在任何一个层次上,如果没有设定autowire,默认为autowire=“false”。
举例来说,如果一个composite元素设定autowire为true,这意味着对于此构件中的所有组件引用,自动连线是可用的。在这个例子中,通过对所关心的组件和引用设置autowire=“false”,从而为特殊的组件和引用关掉自动连线。
对自动连线可用的每一个组件引用来说,自动连线过程就是在构件里寻找与此引用兼容(compatible)的目标服务。这里的“compatible”意味着:
l 目标服务接口必须是引用接口的一个兼容的超集(如the section on Wires中定义的)
l 应用到服务里的intents、bindings和policies必须与引用中的兼容。所以引用与服务的连线不会由于binding和policy不匹配而产生一个错误。
如果对一个特殊的引用,找到了超过1个有效的目标服务,SCA运行时采取的行为依赖于此引用的multiplicity属性:
l multiplicity为0..1或1..1时,SCA运行时(runtime)将选择目标服务之一(如A)与引用连接。这里的目标服务A是依赖于运行时的。
l multiplicity为0..n或1..n时,引用将连接所有的目标服务。
如果对一个特殊的引用,没有找到有效的目标服务,SCA运行时采取的行为依赖于此引用的multiplicity属性:
l multiplicity为0..1或0..n时,没有问题,即没有服务被连接,不会产生错误。
l multiplicity为1..1或1..n时,SCA运行时会报错,因为此引用必须有连接。
1.6.4.3 自动连接实例(Autowire Examples)
下面的例子演示了同一个构件的两个版本。第一个版本是通过显式连线完成的,即没有使用自动连线。第二个版本通过使用自动连线完成。在这两种情况下,结果是一样的,即连接引用与服务的连线是一样的。
图12是这个构件的组装图:

图12. 自动连线的构件实例
首先,使用显式连线的构件代码如下:
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- Autowire Example - No autowire -->
- <composite xmlns:xsd="http://www.w3.org/2001/XMLSchema-instance"
- xmlns="http://www.osoa.org/xmlns/sca/1.0"
- targetNamespace="http://foo.com"
- name="AccountComposite">
-
- <service name="PaymentService" promote="PaymentsComponent"/>
-
- <component name="PaymentsComponent">
- <implementation.java class="com.foo.accounts.Payments"/>
- <service name="PaymentService"/>
- <reference name="CustomerAccountService"
- target="CustomerAccountComponent"/>
- <reference name="ProductPricingService" target="ProductPricingComponent"/>
- <reference name="AccountsLedgerService" target="AccountsLedgerComponent"/>
- <reference name="ExternalBankingService"/>
- </component>
- <component name="CustomerAccountComponent">
- <implementation.java class="com.foo.accounts.CustomerAccount"/>
- </component>
-
- <component name="ProductPricingComponent">
- <implementation.composite class="com.foo.accounts.ProductPricing"/>
- </component>
-
- <component name="AccountsLedgerComponent">
- <implementation.composite class="com.foo.accounts.AccountsLedger"/>
- </component>
-
- <reference name="ExternalBankingService"
- promote="PaymentsComponent/ExternalBankingService"/>
-
- </composite>
其次,使用自动连线的构件代码:
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- Autowire Example - With autowire -->
- <composite xmlns:xsd="http://www.w3.org/2001/XMLSchema-instance"
- xmlns="http://www.osoa.org/xmlns/sca/1.0"
- targetNamespace="http://foo.com"
- name="AccountComposite">
-
- <service name="PaymentService" promote="PaymentsComponent">
- <interface.java class="com.foo.PaymentServiceInterface"/>
- </service>
-
- <component name="PaymentsComponent" autowire="true">
- <implementation.java class="com.foo.accounts.Payments"/>
- <service name="PaymentService"/>
- <reference name="CustomerAccountService"/>
- <reference name="ProductPricingService"/>
- <reference name="AccountsLedgerService"/>
- <reference name="ExternalBankingService"/>
- </component>
-
- <component name="CustomerAccountComponent">
- <implementation.java class="com.foo.accounts.CustomerAccount"/>
- </component>
-
- <component name="ProductPricingComponent">
- <implementation.composite class="com.foo.accounts.ProductPricing"/>
- </component>
-
- <component name="AccountsLedgerComponent">
- <implementation.composite class="com.foo.accounts.AccountsLedger"/>
- </component>
-
- <reference name="ExternalBankingService"
- promote="PaymentsComponent/ExternalBankingService"/>
-
- </composite>
在第二种情况,组件PaymentsComponent设定了自动连线,而且对它的任何引用都没有显式连线。也即连线通过自动连线(autowire)被自动创建。
注意:在第二个例子中,可以不写(omit)PaymentsComponent里的service和reference元素。写在这是为了清楚,但是如果它们不写在这,组件服务和引用依然存在,因为它们被组件使用的实现提供。
1.6.5 把构件作为组件实现来使用
构件可以在高层次的构件中形成组件实现(component implementation)。换句话说,高层次的构件可以有由构件实现的组件。
当一个构件被作为组件实现来使用时,它会定义一个可视界。这个构件中的组件不能直接被使用此构件的组件引用(即高层次的构件中的组件不能直接引用低层次构件中的组件)。高层次的构件中的组件仅仅能连接低层次构件的服务和引用。低层次构件的内部结构对高层次构件中的组件是不可见的。
作为组件实现(component implementation)来使用的构件也必须制定(honor)一个完整性契约(completeness contract)。构件的服务、引用和属性形成了一个契约(使用构件的组件要依赖于它)。构件的完整性概念意味着:
l 构件必须至少有一个服务或引用。在SCA中,一个没有服务也没有引用的组件是没有意义的,因为它不能被连接到任何东西,即它不能提供或消费任何服务。
l 构件提供的每一个服务必须被连接到一个组件服务或构件引用。如果服务没有被连接,意味着在运行时如果服务被调用将会抛出异常。
构件的组件类型(component type)使用composite元素的子元素service、reference、property组成的集合定义。
构件作为组件实现来使用,是通过使用component的子元素implementation.composite来实现的。下面的代码片段展示了这种模式:
- <?xml version="1.0" encoding="ASCII"?>
- <!-- Composite Implementation schema snippet -->
- <composite xmlns="http://www.osoa.org/xmlns/sca/1.0"
- targetNamespace="xs:anyURI"
- name="xs:NCName" local="xs:boolean"? autowire="xs:boolean"?
- constrainingType="QName"?
- requires="list of xs:QName"? policySets="list of xs:QName"?>
-
- ...
-
- <component name="xs:NCName" autowire="xs:boolean"?
- requires="list of xs:QName"? policySets="list of xs:QName"?>*
- <implementation.composite name="xs:QName"/>?
- <service name="xs:NCName" requires="list of xs:QName"?
- policySets="list of xs:QName"?>*
- <interface/>?
- <binding uri="xs:anyURI" name="xs:QName"?
- requires="list of xs:QName"
- policySets="list of xs:QName"?/>*
- <callback>?
- <binding uri="xs:anyURI"? name="xs:QName"?
- requires="list of xs:QName"?
- policySets="list of xs:QName"?/>+
- </callback>
- </service>
- <property name="xs:NCName" (type="xs:QName" | element="xs:QName")
- source="xs:string"? file="xs:anyURI"?>*
- property-value
- </property>
- <reference name="xs:NCName" target="list of xs:anyURI"?
- autowire="xs:boolean"? wiredByImpl="xs:boolean"?
- requires="list of xs:QName"? policySets="list of xs:QName"?
- multiplicity="0..1 or 1..1 or 0..n or 1..n"?/>*
- <interface/>?
- <binding uri="xs:anyURI"? name="xs:QName"?
- requires="list of xs:QName" policySets="list of xs:QName"?/>*
- <callback>?
- <binding uri="xs:anyURI"? name="xs:QName"?
- requires="list of xs:QName"?
- policySets="list of xs:QName"?/>+
- </callback>
- </reference>
- </component>
-
- ...
-
- </composite>
implementation.composite元素有下面的属性:
l name(必需):作为组件实现来使用的构件名称。
1.6.5.1 实例—使用构件作为一个组件实现
下面是一个构件的例子,它包含两个组件,其中每一个组件都是用一个构件实现的:
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- CompositeComponent example -->
- <composite xmlns:xsd="http://www.w3.org/2001/XMLSchema-instance"
- xsd:schemaLocation="http://www.osoa.org/xmlns/sca/1.0
- file:/C:/Strategy/SCA/v09_osoaschemas/schemas/sca.xsd"
- xmlns="http://www.osoa.org/xmlns/sca/1.0"
- targetNamespace="http://foo.com"
- xmlns:foo="http://foo.com"
- name="AccountComposite">
-
- <service name="AccountService" promote="AccountServiceComponent">
- <interface.java interface="services.account.AccountService"/>
- <binding.ws port="AccountService#
- wsdl.endpoint(AccountService/AccountServiceSOAP)"/>
- </service>
-
- <reference name="stockQuoteService"
- promote="AccountServiceComponent/StockQuoteService">
- <interface.java interface="services.stockquote.StockQuoteService"/>
- <binding.ws port="http://www.quickstockquote.com/StockQuoteService#
- wsdl.endpoint(StockQuoteService/StockQuoteServiceSOAP)"/>
- </reference>
-
- <property name="currency" type="xsd:string">EURO</property>
-
- <component name="AccountServiceComponent">
- <implementation.composite name="foo:AccountServiceComposite1"/>
- <reference name="AccountDataService" target="AccountDataService"/>
- <reference name="StockQuoteService"/>
- <property name="currency" source="$currency"/>
- </component>
-
- <component name="AccountDataService">
- <implementation.composite name="foo:AccountDataServiceComposite"/>
- <property name="currency" source="$currency"/>
- </component>
-
- </composite>
1.6.6 通过Inclusion使用构件
为了协助团队开发,构件可能以多个物理部件的形式被开发,然后整合到一个单一的逻辑单元里。
定义在xxx.composite文件里的一个构件可以通过对其它composite文件的包含(inclusion)来接收附加的内容。
Inluded 构件的语义是:通过使用include元素,included构件的内容被内嵌到xxx.composite文件里。它的效果是included构件的文本内容被替换到构件中使用include声明的地方。在这个过程中,被包含的构件元素本身被丢弃了,只有它的内容被包含。
用于包含(inclusion)的composite文件可以有任何内容,但是通常包含一个单一的composite元素。这个composite元素可以包含任何composite元素的有效子元素,比如component、service、reference、wire和include。被包含构件的内容没必要是全部的,因此定义在构件中的部件(artifacts)或在其它相关联的被包含的composite文件里的部件都可以被引用。比如,在一个composite文件里有两个组件是允许的,把其中一个作为源,另一个作为目标,它们之间的连线可以被定义在第二个被包含的composite文件里(也即第二个composite文件引用了第一个composite文件里的两个组件)。
如果来自于inclusion的构件是无效的,将会产生一个错误。比如,这个构件里有重复的元素(例如,不同的included构件发布的相同uri的两个服务),或有不存在的源或目标之间的连线。
下面的代码片段展示了include元素的部分模式。
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- Include snippet -->
- <composite xmlns="http://www.osoa.org/xmlns/sca/1.0"
- targetNamespace="xs:anyURI"
- name="xs:NCName" local="xs:boolean"? autowire="xs:boolean"?
- constrainingType="QName"?
- requires="list of xs:QName"? policySets="list of xs:QName"?>
-
- ...
-
- <include name="xs:QName"/>*
-
- ...
- </composite>
include元素有下面的属性:
l name(必需):被包含的构件名称。
1.6.6.1 被包含构件实例(Included Composite Examples)
下面的图13展示了MyValueComposite2的组装图,它有4个被包含组件。MyValueServices构件包含MyValueService服务。MyValueComponents构件包含MyValueServiceComponent组件和StockQuoteMediatorComponent组件以及它们之间的连线。MyValueWires构件包含了MyValueService服务到MyValueServiceComponent组件的连线以及MyValueServiceComponent 的customerService引用到CustomerService引用的连线,还有StockQuoteMediatorComponent的stockQuoteService引用到StockQuoteService的连线。注意,这仅仅是从被包含构件的集合中构建MyValueComposite2的一个可行的方式。

图12. 用四个被包含构件构建MyValueComposite2
下面的代码展示了MyValueComposite2.composite文件。在这个例子中,此文件仅仅提供了构件的名字。composite文件本身可以用来在一个场景(scenario)中使用被包含的构件去定义组件、服务、引用和连线。
下面的代码片段展示了MyValueServices.composite文件的内容。
下面的代码片段展示了MyValueComponents.composite文件的内容。
下面的代码片段展示了MyValueReferences.composite文件的内容。
下面的代码片段展示了MyValueWires.composite文件的内容。
1.6.7 包含多种类型的组件实现的构件
一个包含多个组件的构件可以有多个组件实现类型。比如,一个构件可以包含一个Java POJO实现的组件,还包含另一个用 |