使用面向
Java 编程语言的 SCA 客户机与实现模型构建和集成应用程序。本文说明了实现示例 SCA 应用程序的基本步骤,包括本地和远程服务以及组装各种服务。
引言
本文将说明开发和部署 SCA 应用程序的主要概念。我们将说明如何创建组件实现来提供远程服务、本地服务、配置属性和服务引用以及如何创建组件、入口点、外边服务和模块。
示例应用程序:Innova Solutions 开发
我们将详细说明一家名为 Innova solutions 的虚构软件公司所进行的活动,该公司向其员工提供不同的服务,以便查看自己的工资单信息、休假详细信息、能力详细信息、个人信息和绩效评级。
以下示例说明了构建用于查看员工的工资单信息的服务的过程,可以通过 Web
应用程序和 Web 服务客户机访问此服务。Innova solutions 将其应用程序实现为两个模块,从而提供了可重用性和灵活性。这两个模块分别为
Payroll 模块和 Web 前端模块:
图 1. Payroll 模块关系图
innovasolutions.payrollmodule 模块表示 payroll
服务,此服务用于使用 Web 服务协议访问遗留系统中的员工工资单信息。它包含以下内容:
Payroll service component:提供远程 payroll
服务,并提供有关员工基本工资、HRA、浮动工资、付薪方式、所得税和特惠税的综合说明。
Payroll data service component:通过接口与遗留系统连接,并向
payroll 服务提供有关基本工资、HRA、浮动工资、奖金和所得税的信息。
External Tax rate rules service:提供不同收入水平的当前税率。
Entry point payroll service:将 payroll
服务通过 Web 服务绑定发布,以供 Web 服务客户机模块及其远程 Web 服务客户机访问。
Assembly:配置并连接模块的所有元素。
下图显示了 Web front-end 模块的不同组件:
图 2. Payroll front-end 模块
innovasolutions.webclientmodule 模块可对用于将信息记录到系统中和访问员工工资单信息的基于浏览器的功能起到促进作用。它包含以下内容:
用于处理 Web 请求和显示员工工资单信息的 login HTML 文件、login
servlet 和 payroll statement JSP。
login service 和 profile service 组件,用于提供管理员工状态的本地服务。
External payroll service:用于访问 innovasolutions.payrollmodule
的远程 payroll 服务。
Assembly:配置和连接模块的所有元素。
应用程序开发
示例应用程序开发涉及到两个 SCA 模块的开发,下面我们将对此进行介绍。
创建 innovasolutions.payrollmodule
SCA 模块 innovasolutions.payrollmodule
是通过这样构建的:在文件系统中构建一个名为 innovasolutions.payrollmodule
的文件夹,并在该文件夹的根目录下放置一个 sca.module 文件。
清单 1 显示了 sca.module 的内容,该文件是一个 xml 文件。
清单 1. sca.module
<?xml version="1.0" encoding="ASCII"?>
<module xmlns="http://www.osoa.org/xmlns/sca/0.9"
name="innovasolutions.payrollmodule">
</module> |
Payroll Data Service Implementation:我们首先创建由
PayrollDataService 服务提供的 PayrollDataService 接口;此服务向其员工提供工资单信息。然后,我们将创建
PayrollDataServiceImpl,以向 Innova solutions 的员工提供 PayrollDataService
服务。
我们创建名为 services/payrolldata 的子目录,并将所有组成
PayrollDataServiceImpl 实现的文件放置到其中。
清单 2 显示了 PayrollDataService Java 接口。
清单 2. PayrollDataService Java 接口
package services.payrolldata;
public interface PayrollDataService {
float getBasic(String employeeID);
float getvariablePay(String employeeID);
float getHRA(String employeeID);
float getProvidentFund(String employeeID);
float getConveyance(String employeeID);
float getIncomeTax(String employeeID);
float getProfessionalTax(String employeeID);
float getNetPay(String employeeID);
} |
清单 3 说明了 PayrollDataServiceImpl Java
实现。
清单 3. PayrollDataServiceImpl Java 实现
package services.payrolldata;
@Service(PayrollDataService.class)
public class payrollDataServiceImpl implements payrollDataService {
public float getBasic(String employeeID){ . . . }
public float getVariablePay(String employeeID){ . . . }
public float getHRA(String employeeID){ . . . }
public float getProvidentFund(String employeeID){ . . . }
float getConveyance(String employeeID){ . . .}
float getProfessionalTax(String employeeID){ . . . }
public float getNetPay(String employeeID){ . . . }
} |
上面的代码片段实现了之前的 PayrollDataService 接口。在实现中使用了一个
@Service Annotation 来声明服务及其接口。
清单 4 显示了上述实现的组件类型、side 文件。
清单 4. 组件类型、side 文件
<xml version="1.0" encoding="ASCII"?>
<componentType xmlns="http://www.osoa.org/xmlns/sca/0.9">
<service name="payrollDataService">
<interface.java interface="services.payrolldata.PayrollDataService"/>
</service>
</componentType> |
Payroll Data Service Component:SCA 组件是通过配置实现的引用和属性创建的。配置引用需要将其连接到其他组件提供的服务或外部服务。此处,我们将通过配置
PayrollDataServiceImpl 创建 PayrollDataServiceComponent。
将使用 component 元素将所创建的 SCA 组件添加到 sca.module
文件,该元素具有一个 name 属性,指定组件的名称。
清单 5 显示了创建 payrollDataServiceComponent
后的 sca.module 文件。
清单 5. 创建了 payrollDataServiceComponent
后的 sca.module 文件
<?xml version="1.0" encoding="ASCII"?>
<module xmlns="http://www.osoa.org/xmlns/sca/0.9"
name="innovasolutions.payrollmodule">
<component name="payrollDataServiceComponent">
<implementation.java class="services.payrolldata.PayrollDataServiceImpl">
</component>
</module> |
创建 TaxRateRules Web 服务外部服务:此处我们将创建一个外部服务
TaxRateRulesService,以提供向 innovasolutions.payrollmodule
的员工提供 TaxRateRulesService 接口的服务。
我们首先创建一个名为 services/taxraterules 的子目录,以将
TaxRateRulesService 外部服务所需的所有文件放入其中。业务合作伙伴实际实现此外部服务,将提供一个
TaxRateRulesService.wsdl。为了处理静态数据类型,我们为 wsdl portType
创建了对应的 Java 接口。
清单 6 显示了 wsdl portType 的 Java 接口的大致情况。
清单 6. wsdl portType 的 Java 接口
package services.taxrate;
public interface TaxRateRulesService {
public float getTaxRate (Float taxableIncome);
} |
接下来,我们将以下代码添加到前面指定的 sca.module 文件,以创建名为
TaxrateRulesService 的外部服务。
清单 7 显示了添加 TaxrateRulesService 后的 sca.module
文件。
清单 7. 添加 TaxrateRulesService 后的 sca.module
文件
<externalService name="TaxRateRulesService">
<interface.java interface="services.taxraterules.TaxRateRulesService"/>
<binding.ws port="http://www.taxrules.com/ TaxRateRulesService #
wsdl.endpoint(TaxRateRulesService / TaxRateRulesService SOAP)"/>
</externalService> |
Payroll Service Implementation:此处我们将讨论
PayrollServiceImpl 的实现,该实现提供一个服务,此服务在 innovasolutions.payrollmodule
中向其员工提供 PayrollService 接口。此实现使用两个其他服务提供的接口引用这两个服务,即
PayrollDataService 接口(本地服务)和 TaxRateRulesService 接口(外部服务)。
我们将首先创建名为 services/payroll 的子目录,并将所有组成
PayrollServiceImpl 实现的文件放入其中。
清单 8 显示了 PayrollService Java 接口。
清单 8. PayrollService Java 接口
package services.payroll;
import org.osoa.sca.annotations.Remotable;
@Remotable
public interface PayrollService{
public PayrollStatement getPayrollStatement(String employeeID); |
上面的 PayrollService Java 接口包含一个 getPayrollStatement()
方法,其参数是 employeeID,将返回 PayrollStatement 对象。由于这需要为外部服务,因此使用
@Remotable Annotation 将接口声明为远程接口。在此实现中,通过远程服务交换的所有参数都是服务数据对象(Service
Data Objects,SDO)类型的数据。
清单 9 显示了 PayrollStatement Java 接口。
清单 9. PayrollStatement Java 接口
package services.payroll;
import java.util.List;
public interface PayrollStatement {
List getPayrollDetails();
float getNetPay();
} |
清单 10 显示了 PaySplitUP Java 接口。
清单 10. PaySplitUP Java 接口
package services.payroll;
public interface PaySplitUP {
String getPaycategory();
void setPaycategory(String payCategory);
void setEarnings();
void setDeductions();
float getEarnings();
float getDeductions();
} |
清单 11 说明了 PayrollServiceImpl Java 实现类。
清单 11. PayrollServiceImpl Java 实现类
package services.payroll;
import java.util.List;
import commonj.sdo.DataFactory;
import org.osoa.sca.annotations.Property;
import org.osoa.sca.annotations.Reference;
import services.payrolldata.PayrollDataService;
import services.taxrate.TaxRateRulesService;
public class PayrollServiceImpl implements PayrollService {
@Property
private String currency = "INR";
@Reference
private PayrollDataService payrollDataService;
@Reference
private TaxRateRulesService taxraterulesService;
public PayrollStatement getPayrollStatement (String employeeID) {
DataFactory dataFactory = DataFactory.INSTANCE;
PayrollStatement payrollStatement =
(PayrollStatement)dataFactory.create(PayrollStatement.class);
List payslip = payrollStatement.getPayrollDetails();
float basic = payrollDataService.getBasic(employeeID);
PlaySplitUP basicSalary
= (PlaySplitUP)dataFactory.create(PlaySplitUP.class);
basicSalary.setPaycategory("BASIC");
basicSalary.setEarnings(currencyConverter(basic));
payslip.add(basicSalary);
. . . . . . . code for HRA . . . .
. . . . . . . code for Variable pay . . . .
. . . . . . . code for conveyance. . . .
. . . . . . . code for Profident fund . . . .
float IncomeTaxAmount = payrollDataService.getIncomeTax(employeeID);
PlaySplitUP IncomeTax
= (PlaySplitUP)dataFactory.create(PlaySplitUP.class);
IncomeTax.setPaycategory("INCOMETAX");
IncomeTax.setDeductions(currencyConverter(IncomeTaxAmount));
payslip.add(IncomeTax);
. . . . . . . code for Professional Tax . . . . . .
return payrollStatement;
}
private float currencyConverter(float value){
if (currency.equals("INR")) return value;
else
if (currency.equals("USD")) return value * 45.5f;
else return 0.0f;
}
} |
上面所示的 PayrollServiceImpl 类实现了 PayrollService
接口。PayrollServiceImpl 使用 @Reference Annotation 定义了两个成员变量,以引用另外两个服务,即
PayrollDataService 和 TaxRateRulesService。SCA 运行时通过注入解析这些引用。PayrollServiceImpl
使用 @Property Annotation 在运行时配置成员变量 currency。PayrollStatement
对象是使用 SDO 数据工厂 API 作为服务数据对象 (SDO) 创建的。
清单 12 显示了上述 PayrollServiceImpl 的组件类型文件。
清单 12. PayrollServiceImpl 的组件类型文件
<?xml version="1.0" encoding="ASCII"?>
<componentType xmlns="http://www.osoa.org/xmlns/sca/0.9"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<service name="PayrollService">
<interface.java interface="services.payroll.PayrollService"/>
</service>
<reference name="payrollDataService">
<interface.java interface="services.payrolldata.PayrollDataService"/>
</reference>
<reference name="stockRatestockQuoteService">
<interface.java interface="services.taxRateRules.TaxRateRulesService"/>
</reference>
<property name="currency" type="xsd:string" default="INR"/>
</componentType> |
Payroll Service Component:现在我们将通过配置上面实现的
PayrollServiceImpl 来创建 PayrollServiceComponent。我们将对上面指定的
sca.module 文件添加若干行代码来包括 PayrollServiceComponent,如清单
13 中所示。
清单 13. 添加了额外代码行的 sca.module 文件
<component name="PayrollServiceComponent">
<implementation.java class="services.payroll.payrollServiceImpl"/>
<properties>
<v:currency>INR</v:currency>
</properties>
<references>
<v:payrollDataService>PayrollDataServiceComponent</v:payrollDataService>
<v:taxRateRulesService>TaxRateRulesService</v:taxRateRulesService>
</references>
</component> |
创建 payroll 服务 Web 服务入口点:下一步我们将创建名为 PayrollService
的入口点来发布 PayrollService,以便 Web 服务客户机能够访问 PayrollService。需要首先创建
SCA 运行时用于绑定到入口点的 WSDL 定义文件,然后才能在 sca.module 文件中创建入口点。我们向
sca.module 文件添加数行代码来表示 PayrollService 入口点的创建。
清单 14 显示了添加到上面指定的 sca.module 文件中的代码行。
清单 14. 添加了额外代码行的指定 sca.module 文件
<entryPoint name="PayrollService">
<interface.java interface="services.payroll.PayrollService"/>
<binding.ws port="http://www.innovasolutions.com/PayrollService#
wsdl.endpoint(PayrollService/PayrollServiceSOAP)"/>
<reference>PayrollServiceComponent</reference>
</entryPoint> |
创建 innovasolutions.webclientmodule
在此部分,我们将创建 Innova Solutions Web 应用程序,以访问名为
payroll service 的外部服务,此服务使用了本地服务组件、SCA 范围管理、JSP 和 Servlet。Innova
Solutions Web 应用程序允许其员工登录并使用范围确定为 HTTP 会话的本地服务跟踪自己的概要,还向其提供了对工资单系统的访问和显示他们每月的工资单。它将首先把用户导航到登录页,然后前进到工资单系统,在其中显示每月的工资单。
以下各个部分将说明如何创建 InnovaSolutions Web 应用程序外部的各个
SCA 服务,即 login、user profile 和 payroll。然后我们将了解如何由 Servlet、JSP
和标记库访问这些服务,以提供用户界面。
我们将首先实现 LoginServiceImpl,此服务负责将用户登录到应用程序中。LoginServiceImpl
提供服务 LoginService,该服务在 innovasolutions.webclientmodule
中向员工提供 LoginService 接口。
首先,我们创建名为 services/profile 的子文件夹,并将属于
LoginServiceImpl 实现的所有文件放入其中。
清单 15 显示了 LoginService Java 接口。
清单 15. LoginService Java 接口
package services.profile;
public interface LoginService{
public static final int SUCCESS = 1;
public static final int INVALID_LOGIN = -1;
public static final int INVALID_PASSWORD = -2;
public int login(String employeeID, String password);
} |
接下来,编写实现 LoningService 接口的 LoginServiceImpl
Java 实现,该实现使用其接口 profileservice 引用本地服务。
清单 16 给出了 LoginServiceImpl Java 实现。
清单 16. LoginServiceImpl Java 实现
package services.profile;
import org.osoa.sca.annotations.Service;
import org.osoa.sca.annotations.Reference;
@Service(LoginService.class)
public class LoginServiceImpl implements LoginService{
@Reference
private ProfileService profileService;
public int login(String employeeID, String password) { …. }
} |
上面的 LoginServiceImpl 实现了 LoginService
接口,并使用其接口 profileservice 引用本地服务。
Login Component:此处我们将通过配置 LoginServiceImpl
实现来创建 LoginServiceComponent。让我们看看显示包含 LoginServiceComponent
的 innovasolutions.webclientmodule 的 sca.module 文件的代码。
清单 17 显示了 innovasolutions.webclientmodule
的 sca.module 文件。
清单 17. innovasolutions.webclientmodule
的 sca.module 文件
<?xml version="1.0" encoding="ASCII"?>
<module xmlns="http://www.osoa.org/xmlns/sca/0.9"
xmlns:v="http://www.osoa.org/xmlns/sca/values/0.9"
name="innovasolutions.webclientmodule">
<component name="LoginServiceComponent">
<implementation.java class="services.profile.LoginServiceImpl"/>
</component>
</module> |
Profile Service Implementation:在此部分,我们将简要地给出
profileServiceImpl,此实现提供了由接口 ProfileService 访问的服务。通过使用
ProfileService,可以在用户的 Web 应用程序内导航时跟踪用户状态。我们使用前面创建的子文件夹
services/profile 来放置组成 profileServiceImpl 实现的所有文件。
profileService Java 接口使用 @Scope Annotation
来声明 ProfileServiceImpl 实例的范围由会话确定。
清单 18 显示了 ProfileService Java 接口。
清单 18. ProfileService Java 接口
package services.profile;
import org.osoa.sca.annotations.Scope;
@Scope("session")
public interface ProfileService{
public String getFirstName();
public void setFirstName(String pName);
public String getLastName();
public void setLastName(String pName);
public boolean isLoggedIn();
public void setLoggedIn(boolean pStatus);
public String getId();
public void setId(String pId);
} |
ProfileServiceImpl 实现了 ProfileService
Java 接口。清单 19 说明了 ProfileServiceImpl Java 实现。
清单 19. ProfileServiceImpl Java 实现
package services.profile;
import org.osoa.sca.annotations.Property;
import org.osoa.sca.annotations.Scope;
import org.osoa.sca.annotations.Service;
@Service(ProfileService.class")
@Scope("session")
public class ProfileServiceImpl implements ProfileService{
@Property
private String firstName;
. . . . . .
}
} |
Profile Service Component:现在我们将清单 20
中所示的代码片段添加到 innovasolutions.webclientmodule 的 sca.module
文件中,从而创建 ProfileServiceComponent。
清单 20. 添加了额外代码行的 sca.module 文件
<component name="ProfileServiceComponent">
<implementation.java class="services.profile.ProfileImpl"/>
<properties>
<v:firstName>Anonymous</v:firstName>
</properties>
</component> |
清单 21 显示了在 component 元素下添加的三行代码 LoginServiceComponent。
清单 21. LoginServiceComponent
<references> <v:profileService>ProfileServiceComponent</v:profileService> </references> |
Payroll Service Web Service External
Service:在此部分,我们将创建名为 PayrollService 的外部服务,该接口在 innovasolutions.webclientmodule
中向用户提供名为 PayrollService 的接口。
我们首先创建一个名为 services/payroll 的子目录,以将
PayrollService 外部服务所需的所有文件放入其中。此外部服务提供一个 PayrollService.wsdl
文件。我们为 wsdl portType 创建对应的 Java 接口,即 PayrollService、PayrollStatement
和 PaySplitUP,以便在使用 PayrollService 时处理静态 Java 类型。
最后,我们添加清单 22 中所示的代码,以在 innovasolutions.webclientmodule
的 sca.module 文件中创建名为 PayrollService 的外部服务。
清单 22. 经过修改以创建 PayrollService 的 sca.module
文件
<externalService name="PayrollService">
<interface.java interface="services.account.PayrollService"/>
<binding.ws port="http://www.innovasolutions.com/PayrollService#
wsdl.endpoint(PayrollService/PayrollServiceSOAP)"/>
</externalService> |
Login HTML 页:login.html 页将当前用户的用户名和密码发送给
login Servlet。
Login Servlet:login Servlet 处理从 login.html
获得的用户名和密码,并使用 ModuleContext API 调用 login 本地服务。CurrentModuleContext.getContext()
返回当前的模块上下文,并随后调用 locateService("LoginServiceComponent")
查询本地服务。
Payroll Statement JSP: PayrollStatement.JSP
显示 payroll 服务返回的员工的所有工资单信息。为了让 Payroll Statement 页不受实现细节的限制,Payroll
Statement.jsp 使用了一系列 JSP 标记,即 login 标记、service 标记和 payroll
status 标记。
部署
以下部分对子系统构件进行说明。
创建 innovasolutions.payrollsubsystem
在此部分,我们将创建 innovasolutions.payrollsubsystem,此子系统对
innovasolutions.payroll 模块进行配置。首先,在文件系统中创建名为 innovasolutions.payrollsubsystem
的文件夹,并在根目录放置 sca.subsystem 文件。
清单 23 显示了 innovasolutions.payrollsubsystem
的 sca.subsystem 文件。
清单 23. innovasolutions.payrollsubsystem
的 sca.subsystem 文件
<?xml version="1.0" encoding="ASCII"?>
<subsystem xmlns="http://www.osoa.org/xmlns/sca/0.9"
name="innovasolutions.payrollsubsytem">
<moduleComponent
name="PayrollModuleComponent"module="innovasolutions.payrollmodule"/>
</subsystem> |
创建 innovasolutions.webclientsubsystem
在此部分,我们将创建 innovasolutions.webclientsubsystem,此子系统对
innovasolutions.webclient 模块进行配置。首先,在文件系统中创建名为 innovasolutions.webclientsubsystem
的文件夹,并在根目录放置一个 sca.subsystem 文件。
清单 24 显示了 innovasolutions.webclientsubsystem
的 sca.subsystem 文件。
清单 24. innovasolutions.webclientsubsystem
的 sca.subsystem 文件
<?xml version="1.0" encoding="ASCII"?>
<subsystem xmlns="http://www.osoa.org/xmlns/sca/0.9"
xmlns:v="http://www.osoa.org/xmlns/sca/values/0.9"
name="innovasolutions.webclientsubsytem">
<moduleComponent name="WebClientModuleComponent"
module="innovasolutions.webclientmodule">
<references>
<v:PayrollService>innovasolutions.payrollsunbsystem/
PayrollModuleComponent/PayrollService</v:PayrollService>
</references>
</moduleComponent>
</subsystem> |
结束语
我们已经演示了应用程序 Innova Solutions 开发过程,以帮助您使用
SCA 客户机和实现模型利用 Java 编程语言构建和集成应用程序。SCA 应用程序提供了服务的可移植性、可重用性和灵活性,从而将开发人员从中间件编程的复杂性中解放出来。 |