7.2. 实现 implementation
这个对应规范SCA Assembly Model V1.00(http://www.osoa.org/display/Main/Service+Component+Architecture+Specifications) 的1.4节
7.2.1. 解释
每个component都应该有一个implementation,它是实现具体业务逻辑的地方。所有component对外提供的service,component的reference对外的引用,component自己内部的逻辑都在这里实现。一个composite也可以是implementation。
Tuscany支持java,bpel,script等很多实现。也就是说component的implementation可以用java代码写,也可以用script来写。
打开Restaurant2.composite,就可以看到component的定义。
<sca:component name="RestaurantServiceComponent">
<sca:implementation.java class="restaurant2.lib.RestaurantServiceImpl"/>
<sca:service name="RestaurantService">
<sca:interface.java interface="restaurant2.api.RestaurantService"/>
</sca:service>
<sca:reference name="menuService"/>
<sca:reference name="billService"/>
</sca:component>
在component下有一个子元素implementation
<sca:implementation.java class="restaurant2.lib.RestaurantServiceImpl"/>
这个表示这个component是java实现的,类名是restaurant2.lib.RestaurantServiceImpl。
7.2.2. 改变implementation
前面说component可以使用其他的实现,现在我们用前面的例子演示一下使用script 实现VatServiceComponent。
在diagram中删掉component VatServiceComponent的实现,选中左上角那个图标,然后右键,选择Delete from Model.
图7_2_1
然后添加script implementation,使用palette来添加。因为在工具条上有两个Add ScriptImplementation,一个是FraSCAti运行环境的,一个tuscany运行环境,要选后者。点Script(Tuscany),然后再点在VatServiceComponent上。
图7_2_2
图7_2_3
在properties的script中填入restaurant2/lib/VatServiceImpl.js
图7_2_4
在目录 src/restaurant2/lib 添加新文件 VatServiceImpl.js.内容为:
运行client,结果为,之前的价格是65.78. 因为这里我们定义的vatRate不同了。
图7_2_5
现在我们再看Restaurant2.composite文件,VatServiceComponent的定义变为
<sca:component name="VatServiceComponent">
<tuscany:implementation.script script="restaurant2/lib/VatServiceImpl.js"/>
<sca:service name="VatService">
<sca:interface.java interface="restaurant2.api.VatService"/>
</sca:service>
</sca:component>
修改之前的样子是
<sca:component name="VatServiceComponent">
<sca:implementation.java class="restaurant.lib.VatServiceImpl"/>
<sca:service name="VatService">
<sca:interface.java interface="restaurant.api.VatService"/>
</sca:service>
</sca:component>
这个implementation是可以自己定义新的implementation,而且一定会自己定义。在系统实施之前一定预先开发出一些implementation,这样在实施的时候可以减少大部分的代码工作。
7.2.3. Component Type
service,reference和property是在实现里可配置的方面。SCA将这三个东西的配置整体叫做component type。他们的属性在component定义里描述。通过component type,实现可以声明他包含的service,reference和property,同时实现也能为所有service,reference和property的属性设置值。
service,reference和property的属性都可以通过implementation对应的component的配置来覆盖,component也可以决定并不覆盖那些属性。某些属性是不能覆盖的,比如意图。
图7_2_6
做个简单的例子,说明什么是component type。
7.2.3.1. 演示例子
Ø 创建一个component,叫做HelloWorldServiceComponent
图7_2_7
Ø 添加java implementation,class name是helloworld.HelloWorldImpl
Ø Helloworld.composite内容
<?xml version="1.0" encoding="UTF-8"?>
<composite xmlns="http://www.osoa.org/xmlns/sca/1.0" xmlns:hw="http://helloworld" name="helloworld" targetNamespace="http://helloworld">
<component name="HelloWorldServiceComponent">
<implementation.java class="helloworld.HelloWorldImpl"/>
</component>
</composite>
Ø 添加接口类
Ø 实现类
Ø 测试类
Ø 运行client。
输出为====You are welcome, Neo
图7_2_8
7.2.3.2. 例子说明
在实现类HelloWorldImpl里,
@Service(HelloWorldService.class)
@Property
这两个就是component type定义,一个是定义service,一个是定义Property。他是通过java的annotation来实现。其他类型的实现,有其他的方式定义。这里演示的只是针对java implementation. 再去看Helloworld.composite的定义,你会发现这个component的定义只有implementation,没有service的定义。但我们在测试类里可以获得service,那个这个service就是implementation类HelloWorldImpl通过 @service 定义的。如果删掉@Service(HelloWorldService.class),再运行client,你会看到:
Exception in thread "main" org.osoa.sca.ServiceRuntimeException: No matching operation for getGreetings is found in service HelloWorldServiceComponent#HelloWorldImpl
7.2.3.3. component的配置来覆盖Implementation中定义
在component上定义属性welcomeMsg。
Ø 在palette上选择property
图7_2_9
Ø 添加到component上,命名为welcomeMsg
图7_2_10
Ø 设置值为How are you,
图7_2_11
Ø 运行client,
输出结果变为====How are you,Neo
图7_2_12
7.2.4. .componentType文件
7.2.4.1. 说明
前面提到一个component type由service,reference,property组成。Component type是通过两步来确定。第一步是inspection方式,SCA自己通过代码中的annotation来计算获得component type,像前面的Service的定义。。第二步是解决那些通过第一种方式不可能定义的情况,或者通过第一种方式不能定义完整的信息,第二步是第一步的补充。在理想的情况下,component type是通过第一步完全定义。第二步是通过一个.componentType文件来实现定义。 SCA在解析component的时候,如果.componentType文件存在,会同时解析这个文件。在component type文件定义的Component type信息必须与从inspection方式获得的信息兼容。
7.2.4.2. 例子
拿前面那个project继续。前面我们测试过,如果删掉HelloWorldImpl里的@service,运行时就会抛出No matching operation Exception。下面我们通过.componentType文件来定义component type。
Ø 删掉HelloWorldImpl里的@service
Ø 添加.componentType文件,在package helloworld上右键,选择【new > other】,选择SCA Component Type,点next
图7_2_13
Ø 在file name上填 HelloWorldImpl.componentType, 这个文件的名字一定要和实现类的名字相同。点finish
图7_2_14
Ø Eclipse会自动打开component type编辑器
图7_2_15
Ø 填入
<service name="HelloWorldImpl">
<interface.java interface="helloworld.HelloWorldService"/>
</service>
图7_2_16
Ø 运行client,得到结果
图7_2_17
这里你可能注意到service的名字是HelloWorldImpl,这个目前只能是这个名字,原则上讲这个可以定义其他名字,但tuscany目前这里有个问题。在tuscany的实现里,当构建runtime的component的时候,如果一个实现类没有定义@service,那么它自动加一个service给component,名字为实现类的名字。所以如果在.componentType里定义了另外一个serivce名字,tuscany会抛出一个exception:More than one service is declared on component HelloWorldServiceComponent. 另外tuscany对componentyType中的property定义也有问题,无法获得componentyType文件中定义的property的值。