每个组件的的实现均提供了组件的业务逻辑,通过implementation type指定组件实现的所用的技术。
1. 实现SCA组件
(1) Implementation Type
<composite name="cart"
....>
<component name="ShoppingCart" >
<implementation.java class="com.tuscanyscatours.impl.ShoppingCartImpl" />
....
</component>
<component name="Payment"
xmlns:pp="http://www.tuscanyscatours.com/Payment">
<implementation.bpel process="pp:Payment" />
....
</component>
</composite>
SCA规范定义了默认的Java实现类型:BPEL, C++,C,COBOL,Spring,.war,EJB,.ear,同时SCA还提供了扩展点用
与客制化定义自己的实现类型。
(2) 配置SCA组件使用组件定义
该配置文件是一个以.composite结尾的XML文件,一个相同的SCA组件实现可以被不同的组件用不同的配置方式
进行配置,如附件中:汽车租赁组件实现定义了一个minAge属性用于将组件实现定义成适合不同的应用场合。
(3) 发现或定义组件类型
SCA使用两种不同的途径去发现和定义组件的组件类型,依赖于底层的实现技术是否提供了便利用于编程式的验证
它的实现类型(即:Introspecting).对于支持Introspection的实现类型(JAVA,BPEL),SCA定义了规则用于获
取组件实现类型, 而对不支持Introspecting的实现类型,组件类型的定义必须提供一个但单独的XML文件(With
Extension:.componentType )。例如下面的代码没有使用SCA 注解:
public class AirportCodes {
public String getAirport(String code) {
if ("AAA".equals(code)) return "Anaa";
else if ("AAB".equals(code)) return "Arrabury";
// other airport codes and cities would follow here
else return null;
}
}
此时不需要提供组件类型定义文件,因为Tunscany能够通过实现类型自动获取组件类型,等价与下面的XML
文件:
<componentType xmlns="http://www.osoa.org/xmlns/sca/1.0">
<service name="AirportCodes">
<interface.java interface="com.tuscanyscatours.AirportCodes" />
</service>
</componentType>
2. 使用组件去提供服务
(1) 定义服务:@Service注解
package com.tuscanyscatours.usingsca.impl;
import com.tuscanyscatours.Bookings;
import org.osoa.sca.annotations.Service;
@Service(Bookings.class)
public class TripBookingImpl implements Bookings {
....
public String newBooking(String trip, int people) {
....
}
}
package com.tuscanyscatours;
import org.osoa.sca.annotations.Remotable;
@Remotable
public interface Bookings {
String newBooking(String trip, int people);
}
如果组件实现上没有注解@Service,则SCA默认组件实现拥有所有实现的接口的服务,这些服务拥有注解:
@Remotable;而如果接口拥有注解:@Remotable,则将忽略实现类上的@Service注解。
总结: SCA将服务的定义委托给组件的实现并且允许每个组件实现类型用自己的方式去处理,因为SCA需
要所有的实现类型支持相同的服务和组件定义语义并且可以正常工作,而且这些语义是内嵌在SCA的组件
类型的定义中的。这种一致性保证了所有的SCA服务和组件可使用相同的方式进行配置和组合,而不管是
使用哪一种技术来实现组件的,reference和properties也采用的是这种思想。
(2) SCA种口定义
SCA定义接口是通过不同的interface types来定义的,例如下面是一个基于WSDL1.1portType定义的接口:
<interface.wsdl interface=
"http://tuscanyscatours.com/#wsdl.interface(Bookings)" />
基于Java Interface定义的接口:
<interface.java interface="com.tuscanyscatours.Bookings" />
(3) 组件定义中配置服务
组件的定义文件中可以指定服务的配置信息,可以改变服务的接口而使用不同的接口语言,如将interface.
java改成interface.wsdl;同时,组件定义时可以覆写组件实现的方法中的一些方法从而成为原组件服务接
口的一个子集,组件定义中可以添加一些方法或其他的服务,而这些方法或服务没有在组件实现中定义;当
然组件定义中也可以移除组件实现中定义的一些服务;如果组件的定义中没有指定服务的配置,那么将根据
组件类型的默认discovery rules计算出组件的服务。例如:
<component name="TripBooking">
<implementation.java class="com.tuscanyscatours.usingsca.impl.TripBookingImpl" />
</component>
该组件没有定义服务,根据默认的计算规则该interface type应该是:interface.java.
默认情况下,实现的组件类型的services, references,properties自动的成为组件的一部分,除非在组件
定义文件中明确的指定。
(4) Local and Remotable Interface
SCA 支持本地和远程的interfaces,本地接口只能被运行的相同操作系统(本地调用)调用,而远程接口的服
务即可被远程调用也可被本地调用,是可被运行在不同Process或不同操作系统的Process调用。
Interface定义为interface.wsdl只能被用于远程调用 ,而interface.java即可被远程调用也可被本地调
用,若要被远程调用需要在接口上添加注解:@Remotable.
对本地调用的接口,参数和返回值是通过reference(shared)传递的 ,对调用接口的代码而言,接口实现
类的任何改变都是透明的;对远程调用的接口,参数和返回值是通过value(copied)传递的 ,对调用接口的
代码而言,接口实现类的任何改变都是不可见的。通过传reference可能更有效,但是却创建了一个更紧簇
的依赖,调用代码和服务实现之间的依赖;通过传value意味着调用代码和服务实现之间几乎是没有依赖的,
但是copying data 却是昂贵的,特别是在大批量数据传递时。为了避免本地和远程调用过程中的缺陷,
SCA和Tuscany提供看了优化功能用于许多常见的场合。
(5) 回调和双向接口
双向接口:一个接口作为服务请求者去调用另一个服务提供者接口,而服务提供者再去调用服务请求者,这
个过程也叫回调。服务请求者接口使用interface属性而服务提供者使用callbackInterface接口,例如:
<interface.java interface="com.tuscanyscatours.common.Search"
callbackInterface="com.tuscanyscatours.common.SearchCallback" />
双向接口可以是本地或远程的,但是 不能给一个本地的接口指定一个远程的回调接口,相反也不成立。
(6)Conversational(会话)Interfaces
对interface.java,接口可被标注为回话接口通过使用@Conversational 注解在Java接口上,对interface
.wsdl SCA已经定义了一个全局的属性requires在SCa的命名空间里,该属性用于标注一个WDL1.1或
WSDL2.0的interface元素作为一个回话接口。
回话接口可以是本地的或者是远程的,也可以将双向接口定义成回话接口。
3. 使用Reference 和Wires连接组件
(1) 定义引用
public class TripBookingImpl implements Bookings {
public TripBookingImpl(@Reference(name="cars") Cars cars ) {
this.cars = cars;
}
protected Cars cars;
@Reference
protected Flights flights;
private Hotels hotels;
@Reference
public void setHotels(Hotels hotels) {
this.hotels = hotels;
}
....
}
(2) Wiring Reference to Service
Reference和Service之间的连接叫做:wire,而连接的过程叫做:wiring; Tuscany引用一个已经部署的组件在
组件的实现代码执行之前。
<composite xmlns="http://www.osoa.org/xmlns/sca/1.0"
targetNamespace="http://tuscanyscatours.com/"
name="bookings1">
<component name="TripBooking">
<implementation.java class="com.tuscanyscatours.usingsca.impl.TripBookingImpl" />
<reference name="cars" target="CarPartner/Cars" />
<reference name="flights" target="FlightPartner/Flights" />
<reference name="hotels" target="HotelPartner" />
</component>
<component name="CarPartner">
<implementation.java class="com.tuscanyscatours.usingsca.impl.CarVendorImpl" />
</component>
<component name="FlightPartner">
<implementation.java class="com.tuscanyscatours.usingsca.impl.FlightPartnerImpl" />
</component>
<component name="HotelPartner">
<implementation.java class="com.tuscanyscatours.usingsca.impl.HotelPartnerImpl" />
</component>
</composite>
如果target组件只有一个服务,则只需指定组件的名字,如: target="HotelPartner",否则需按照:组将名称
/服务名称,来命名。
当一个reference和一个service被wired时,reference的接口和service的接口必须一致,即service接口中必
须提供所有的reference接口的方法,相同的输入,输出,返回值、议程等信息;当然service也可以提供附加的
方法是reference中不存在的,此时SCA规范这是一个"Compitale SuperSet "; 但对双向的接口,reference回
调的接口必须与service回调接口的的方法的Compitable Superset一致,因为服务请求着和服务提供者在进行回
调时是被颠倒的。
如果reference和service的interface type是不同的,比如reference的接口类型是interface.jav而service的
接口类型是interface.wsdl,这是SCA规则需要使用Tuscany的Java-To-WDL 映射(JAX-WS定义的)将reference
的接口转换成一个WSDL1.1的portType与服务的接口进行比较,在这种情况下,interface需要定义成
remotable的而且不允许方法重载,reference方法中的参数和返回值需要转换成XML Scheme类型(使用JAXB
或SDO映射);如果比较成功则wiring成功,否则失败。
(3) Wire Elements
<composite xmlns="http://www.osoa.org/xmlns/sca/1.0"
targetNamespace="http://tuscanyscatours.com/"
name="bookings2">
<component name="TripBooking">
<implementation.java class="com.tuscanyscatours.usingsca.impl.TripBookingImpl" />
<reference name="cars" target="CarPartner/Cars" />
<reference name="flights" target="FlightPartner/Flights" />
</component>
<wire source="TripBooking/hotels" target="HotelPartner" />
....
</composite>
Wire元素是reference元素属性target的替代,这种配置方式将wire的配置与组建的定义分离出来,允许wiring
的改变而不影响组建的定义,另外这种配置支持当组建部署时而不需被wired,即组建的部署和wiring是分离的。
(4) Automatic wiring
<composite xmlns="http://www.osoa.org/xmlns/sca/1.0"
targetNamespace="http://tuscanyscatours.com/"
name="bookings3">
<component name="TripBooking" autowire="true" >
<implementation.java class="com.tuscanyscatours.usingsca.impl.TripBookingImpl" />
</component>
<component name="CarPartner">
<implementation.java class="com.tuscanyscatours.usingsca.impl.CarVendorImpl" />
</component>
<component name="FlightPartner">
<implementation.java class="com.tuscanyscatours.usingsca.impl.FlightPartnerImpl" />
</component>
<component name="HotelPartner">
<implementation.java class="com.tuscanyscatours.usingsca.impl.HotelPartnerImpl" />
</component>
</composite>
这种配置下,Tuscany将自动wire组件定义中的每一个reference至同一个组件定义中匹配的service
interface, 如果有多个匹配的service被找到,自动wire规则将进行随机选择,而这个选择结果不是开发人员所
期望的,因此这是一种不推荐的配置方式。
(5) Reference Multiplicity
Reference元素的multiplicity属性指定了reference可用的wire数量:
multiplicity="1..1":reference只wire一个单独的service;
multiplicity="1..n": reference wire一个或多个service;
multiplicity="0..1": reference wire零个或1个service;
multiplicity="0..n": reference wire零个或多个service;
<componentType xmlns="http://www.osoa.org/xmlns/sca/1.0">
<service name="Cars">
<interface.java interface="com.tuscanyscatours.Cars" />
</service>
<reference name="cars" multiplicity="1..n" >
<interface.java interface="com.tuscanyscatours.Cars" />
</reference>
<reference name="luxuryCars" multiplicity="0..n" >
<interface.java interface="com.tuscanyscatours.Cars" />
</reference>
</componentType>
服务实现中reference的multiplity的定义时通过实现类型的规则来决定的,对Java实现而言,@Reference注解
有一个required 成员(true或false)来指定注入是否是可选的,而Array或Collection作为reference意味着
reference是mutiplity的,required的默认值是true.
(6) Wiring 使用不同的multiplicities
A. Wiring references with different multiplicities:
<composite xmlns="http://www.osoa.org/xmlns/sca/1.0"
targetNamespace="http://tuscanyscatours.com/"
name="carbookings1">
<component name="CarPartner">
<implementation.java class="com.tuscanyscatours.usingsca.impl.CarPartnerImpl" />
<reference name="cars" target="JoesCars KensCars" />
</component>
<component name="JoesCars">
<implementation.java class="com.tuscanyscatours.usingsca.impl.CarVendorImpl" />
</component>
<component name="KensCars">
<implementation.java class="com.tuscanyscatours.usingsca.impl.CarVendorImpl" />
</component>
</composite>
B. Wiring references with different multiplicities using <wire> elements:
<composite xmlns="http://www.osoa.org/xmlns/sca/1.0"
targetNamespace="http://tuscanyscatours.com/"
name="carbookings2">
<component name="CarPartner">
<implementation.java class="com.tuscanyscatours.usingsca.impl.CarPartnerImpl" />
</component>
<wire source="CarPartner/cars" target="JoesCars" />
<wire source="CarPartner/cars" target="KensCars" />
<component name="JoesCars">
<implementation.java class="com.tuscanyscatours.usingsca.impl.CarVendorImpl" />
</component>
<component name="KensCars">
<implementation.java class="com.tuscanyscatours.usingsca.impl.CarVendorImpl" />
</component>
</composite>
C. Wiring references with different multiplicities using autowire:
<composite xmlns="http://www.osoa.org/xmlns/sca/1.0"
targetNamespace="http://tuscanyscatours.com/"
name="carbookings3">
<component name="CarPartner" autowire="true" >
<implementation.java class="com.tuscanyscatours.usingsca.impl.CarPartnerImpl" />
<reference name="luxuryCars" autowire="false" />
</component>
<component name="JoesCars">
<implementation.java class="com.tuscanyscatours.usingsca.impl.CarVendorImpl" />
</component>
<component name="KensCars">
<implementation.java class="com.tuscanyscatours.usingsca.impl.CarVendorImpl" />
</component>
</composite>
配置中CarPartner将自动wire JoesCars和KensCars Service,因为CarVendorImpl和CarVendorImpl实
现了相同的接口;因为reference luxuryCars与reference car有相同的接口,而我们并不期望 luxuryCars
wire至 JoesCars和KensCars Service,所以将luxuryCars的autowire设为false.
总结:在上面的A、B、C三种配置中,推荐使用第二种。
4. Configuring components using properties
(1) 定义Properties
通过@Property注解注入属性,Defining properties for a component implementation:
public class CurrencyConverterImpl implements CurrencyConverter {{
@Property
protected String fromCurrency;
@Property
protected String toCurrency;
public BigDecimal convert(BigDecimal amount) {
return amount.multiply(getRate(toCurrency))
.divide(getRate(fromCurrency), 2, 0);
}
private BigDecimal getRate(String currency) {
....
}
}
(2) 配置Properties的值
Configuring property values in component definitions:
<composite xmlns="http://www.osoa.org/xmlns/sca/1.0"
targetNamespace="http://tuscanyscatours.com/"
name="converter">
<component name="EURJPYConverter">
<implementation.java class="com.tuscanyscatours.usingsca.impl
.CurrencyConverterImpl" />
<property name="fromCurrency">EUR</property>
<property name="toCurrency">JPY</property>
</component>
<component name="USDGBPConverter">
<implementation.java class="com.tuscanyscatours.usingsca.impl
.CurrencyConverterImpl" />
<property name="fromCurrency">USD</property>
<property name="toCurrency">GBP</property>
</component>
</composite>
(3) Using Complex types for Properties
配置方式1: 使用XMLScheme的complex type作为SCA Property的type.
XML Schem配置:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:t="http://tuscanyscatours.com/"
targetNamespace="http://tuscanyscatours.com/">
<!-- XML schema global element definition for SCA property -->
<xs:element name="billingAddress">
<xs:complexType>
<xs:sequence>
<xs:element name="street" type="xs:string" />
<xs:element name="city" type="xs:string" />
<xs:element name="state" type="xs:string" />
<xs:element name="zip" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
<!--XML schema type definition for SCA property -->
<xs:complexType name="Address">
<xs:sequence>
<xs:element name="street" type="xs:string" />
<xs:element name="city" type="xs:string" />
<xs:element name="state" type="xs:string" />
<xs:element name="zip" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:schema>
对应的实体类:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"street",
"city",
"state",
"zip"
})
@XmlRootElement(name = "billingAddress")
public class BillingAddress {
@XmlElement(required = true)
protected String street;
@XmlElement(required = true)
protected String city;
@XmlElement(required = true)
protected String state;
@XmlElement(required = true)
protected String zip;
//getter/setter方法
......
}
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Address", propOrder = {
"street",
"city",
"state",
"zip"
})
public class Address {
@XmlElement(required = true)
protected String street;
@XmlElement(required = true)
protected String city;
@XmlElement(required = true)
protected String state;
@XmlElement(required = true)
protected String zip;
//getter/setter方法
......
}
注入该实体类:
public class CustomerImpl implements CustomerInfo {
@Property
protected BillingAddress billingAddress;
@Property
protected Address deliveryAddress;
......
}
Compisite配置文件:
<composite xmlns="http://www.osoa.org/xmlns/sca/1.0"
targetNamespace="http://tuscanyscatours.com/"
xmlns:t="http://tuscanyscatours.com/"
name="orders1">
<component name="Customer">
<implementation.java
class="com.tuscanyscatours.usingsca.impl.CustomerImpl" />
<property name="billingAddress" element="t:billingAddress" >
<t:billingAddress xmlns="">
<street>123 Main Street</street>
<city>New York</city>
<state>NY</state>
<zip>01234</zip>
</t:billingAddress>
</property>
</component>
</composite>
配置方式2:使用element的type属性替代property的element属性。
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://tuscanyscatours.com/orders"
xmlns:t="http://tuscanyscatours.com/">
<xs:element name="address" type="t:Address" />
</xs:schema>
SCA configuration for properties defined using a schema type:
<composite xmlns="http://www.osoa.org/xmlns/sca/1.0"
targetNamespace="http://tuscanyscatours.com/"
xmlns:t="http://tuscanyscatours.com/"
xmlns:o="http://tuscanyscatours.com/orders"
name="orders2">
<component name="Customer">
<implementation.java
class="com.tuscanyscatours.usingsca.impl.CustomerImpl" />
<property name="billingAddress" type="t:Address">
<o:address xmlns="">
<street>123 Main Street</street>
<city>New York</city>
<state>NY</state>
<zip>01234</zip>
</o:address>
</property>
<property name="deliveryAddress" type="t:Address">
<o:address xmlns="">
<street>456 Market Street</street>
<city>San Francisco</city>
<state>CA</state>
<zip>98765</zip>
</o:address>
</property>
</component>
</composite>
5. Enabling communication flexibility using bindings
(1) Configuring bindings for services and references
<composite xmlns="http://www.osoa.org/xmlns/sca/1.0"
targetNamespace="http://tuscanyscatours.com/"
name="bookings4">
<component name="TripBooking">
<implementation.java
class="com.tuscanyscatours.usingsca.impl.TripBookingImpl" />
<service name="Bookings">
<binding.ws uri="http://tuscanyscatours.com:8085/Bookings" />
<binding.jms uri="jms:Bookings" />
</service>
<reference name="cars">
<binding.ws uri="http://tuscanycars.com:8081/Cars" />
</reference>
<reference name="flights">
<binding.ejb uri="corbaname:rir:#flight/FlightPartnerHome" />
</reference>
<reference name="hotels" target="HotelPartner" />
</component>
<component name="HotelPartner">
<implementation.java
class="com.tuscanyscatours.usingsca.impl.HotelPartnerImpl" />
</component>
</composite>
(2) The default binding:binding.sca
这种默认的Bingding只用于连接reference至service在同一个domain中,如果是跨域的Binding必须制定具体
的Binging技术:binding:ws或binding.jms.
(3) Domai,binding, and wiring
SCA Domain是SCA组件部署和管理的边界,是一个Server或集群;同一个domain中的Reference和service
可使用wires连接起来,可使用默认的bingding策略,因为SCA会保证在同一domain中这种binding是一致的。
提供服务组件定义:
<composite xmlns="http://www.osoa.org/xmlns/sca/1.0"
targetNamespace="http://tuscanyscahotels.com/"
name="hotelsdomain">
<component name="HotelPartner">
<implementation.java class=
"com.tuscanyscatours.usingsca.impl.HotelPartnerImpl" />
<service name="Hotels">
<!--供外部的domain使用的服务-->
<binding.ws uri=
"http://tuscanyscahotels.com:8083/Hotels" />
<!--供本domain使用过的服务-->
<binding.sca />
</service>
</component>
<component name="HotelOffers">
<implementation.java class=
"com.tuscanyscahotels.impl.HotelOffersImpl" />
<!--这个reference 使用上面的binding.sca提供的服务-->
<reference name="hotels" target="HotelPartner/Hotels" />
</component>
</composite>
消费服务组件定义:
<composite xmlns="http://www.osoa.org/xmlns/sca/1.0"
targetNamespace="http://tuscanyscatours.com/"
name="toursdomain">
<component name="TripBooking">
<implementation.java
class="com.tuscanyscatours.usingsca.impl.TripBookingImpl" />
<reference name="flights">
<binding.ws
uri="http://flightbookingservice.com:8084/Flights" />
</reference>
<reference name="hotels">
<binding.ws uri="http://tuscanyscahotels.com:8083/Hotels" />
</reference>
<reference name="cars" target="CarPartner/Cars" />
</component>
<component name="CarPartner">
<implementation.java
class="com.tuscanyscatours.usingsca.impl.CarVendorImpl" />
</component>
</composite>
(4) Reference和Service 连接总结
A. 同一个SCA domain中connect reference 和service时,可以使用下面的策略:
■ Use a wire with the default binding
■ Use a wire with an interoperable(能共同操作的) binding
■ Configure the reference and service with matching bindings
B. 不在同一个SCA domain中connect reference 和service时,使用匹配的interoperable bindings进行
配置reference和service;
C. 连接SCA reference或service至非SCA代码时,可以使用匹配的interoperable bindings进行配置
reference和service.