iPOJO 高级样例

本示例演示iPOJO的高级特性

故事情景:
本样例是一个非常简单的应用。客户使用vendor服务,根据适当的提供者购买热狗或者爆米花。两个商家都实现了
vendor服务。热狗商从其他2个服务取得材料(面包片和红肠)。为了销售爆米花,爆米花商家必须保证有足够的玉米库存。




*********************************************************************************************************
(1)创建vendor.services项目

D:\TDDownload\OSGi\MavenSample>mvn archetype:create -DgroupId=iPOJOTutorial -Dar
tifactId=vendor.services -Dversion=1.0.0 -DpackageName=org.apache.felix.ipojo.ex
ample.vendor.service.ingredient

(2)在org.apache.felix.ipojo.example.vendor.service包下定义了2个接口Vendor和Product

Vendor职责是sell Product
#########################################################################################################
package org.apache.felix.ipojo.example.vendor.service;

/**
* Vendor service interface.
*/
public interface Vendor {
/**
* Sells a product.
* @return the sold product.
*/
public Product sell();
}
#########################################################################################################
package org.apache.felix.ipojo.example.vendor.service;

/**
* A sold product.
* Products are sold by Vendors.
*/
public interface Product {

/**
* Gets the product type.
* @return the product type.
*/
String getProductType();

/**
* Gets the product origin.
* @return the product store location.?
*/
String getProductOrigin();

}
#########################################################################################################
(3)在org.apache.felix.ipojo.example.vendor.service.ingredient包下定义了热狗的原材料供应接口Bun和Wiener
#########################################################################################################
package org.apache.felix.ipojo.example.vendor.service.ingredient;

/**
* A very simple service interface to get buns.
*/
public interface Bun {

/**
* Gets a bun
*/
void getBun();

}
#########################################################################################################
package org.apache.felix.ipojo.example.vendor.service.ingredient;

/**
* A very simple service interface to get wieners.
*/
public interface Wiener {

/**
* Gets a wiener.
*/
void getWiener();

}
#########################################################################################################

(4)编辑pom.xml文件:
<packaging>jar</packaging>修改为<packaging>bundle</packaging>
并增加如下内容
<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>1.4.3</version>
<extensions>true</extensions>
<configuration>
<instructions>
<Bundle-SymbolicName>
${pom.artifactId}
</Bundle-SymbolicName>
<ExportPackage>
org.apache.felix.ipojo.example.vendor.service,org.apache.felix.ipojo.example.vendor.service.ingredient
</Export-Package>
</instructions>
</configuration>
</plugin>
</plugins>
</build>

*********************************************************************************************************
接下来我们将编写一个组件,实现热狗商的原料供应服务。在本组件中,我们同时提供了2个服务。

*********************************************************************************************************

Writing a component providing two service
vendor.buns-and-wieners项目

(1)创建项目vendor.buns-and-wieners项目

D:\TDDownload\OSGi\MavenSample>mvn archetype:create -DgroupId=iPOJOTutorial -Dar
tifactId=vendor.buns-and-wieners -Dversion=1.0.0
-DpackageName=org.apache.felix.ipojo.example.vendor.provider

热狗商要同时需要bun服务和wiener服务。在我们的应用中,这些服务由同一组件来提供。
public class BunWienerProvider implements BunService, WienerService {

public void getBun() {
System.out.println("Get a bun");
}

public void getWiener() {
System.out.println("Get a wiener");
}
}

这个类实现了2个服务接口。组件描述(metadata.xml):

<ipojo>
<component
classname="org.apache.felix.ipojo.example.vendor.provider.BunWienerProvider"
name="buns_and_wieners" public="false">
<provides/>
</component>

<instance component="buns_and_wieners"/>
</ipojo>


在本描述内容中,我们定义了组件类型。“classname”是组件实现类的全名字。"name"属性是组件类型名称。
它仅被用于引用该类型(别名?)。

"public=false"属性禁止工厂暴露。一个组件类型发布一个工厂,提供了在描述外部创建该类型实例的方法。在本例中,我们想保证仅有一个实例被创建,所以我们禁止了工厂机制。

在运行时,iPOJO管理服务的发布和自动供应。“provides”意味着组件供应的服务。如果该元素没有提供,iPOJO会将该类实现的所有接口发布成服务。


最后,我们创建了一个组件的实例。实例包含了组件定义的属性,我们使用了组件类型名称连接到目标组件类型上。

在运行时,bundle包含这个组件,将创建一个实例向外提供BunService和WienerServie。


pom.xml文件内容较长,请参考项目根目录下文件。


*********************************************************************************************************
上面我们实现了热狗商的原料供应服务。现在主要焦点是去实现产品供应商服务Vendor。本故事场景中,有2个Product供应商,一个销售热狗、一个是销售爆米花。从服务上来说,两者没有任何产品,但是从实际角度考虑,我们希望能将两者区分开来。下面我们将使用服务属性来达到区分二者的目的。

首先,我们还是先来实现爆米花服务商。
(1)创建vendor.popcorn项目
D:\TDDownload\OSGi\MavenSample>mvn archetype:create -DgroupId=iPOJOTutorial -Dar
tifactId=vendor.popcorn -Dversion=1.0.0
-DpackageName=org.apache.felix.ipojo.example.vendor.popcorn

(2)分别实现product和vendor
###########################################################################################
package org.apache.felix.ipojo.example.vendor.popcorn;

import org.apache.felix.ipojo.example.vendor.service.Product;


public class PopCorn implements Product {


public static final Product NO_MORE_POPCORN = new Product() {
public String getProductOrigin() {
return "D & P";
}

public String getProductType() {
return "no more pop corn";
}
};

public String getProductOrigin() {
return "D & P";
}

public String getProductType() {
return "popcorn";
}

}
#####################################################################################
package org.apache.felix.ipojo.example.vendor.popcorn;

import org.apache.felix.ipojo.example.vendor.service.Product;
import org.apache.felix.ipojo.example.vendor.service.Vendor;

public class PopCornVendor implements Vendor {


private int m_corn_stock;


private boolean m_can_sell = true;


public synchronized Product sell() {
m_corn_stock--;
if (m_corn_stock == 0 && m_can_sell) { // Last pop corn
m_can_sell = false;
System.out.println("Stop selling popcorn ... Run out of stock");
return new PopCorn();
} else if (m_corn_stock > 0) { // Normal case
return new PopCorn();
} else { // Cannot serve.
return PopCorn.NO_MORE_POPCORN;
}
}


public synchronized void refillStock(int newStock) {
m_corn_stock += newStock;
System.out.println("Refill the stock : " + m_corn_stock);
if (m_corn_stock > 0) {
m_can_sell = true;
}
}
}

#####################################################################################
(3)下面主要考察一下metadata.xml关于组件和实例的描述
<ipojo>
<component classname="org.apache.felix.ipojo.example.vendor.popcorn.PopCornVendor" name="popcorn" architecture="true">
<provides/>
<controller field="m_can_sell"/>-----生命周期控制,当m_can_sell变为false时,组件状态为invalid
当这个字段变为true时,组件重新变为可用。
<properties>
<property name="stock" method="refillStock" value="5"/>-----通过方法补充库存
</properties>
</component>

<instance component="popcorn" name="SuperPopCorn">
<property name="managed.service.pid" value="Super.PopCorn.Stock"/>
</instance>
</ipojo>


下面考察vendor.corn.transporter项目,主要用于对爆米花库存的增加。
实现手段使用了配置管理服务:


*****************************************************************************************


Publishing service 属性
(1)创建vendor.hotdog项目
mvn archetype:create -DgroupId=iPOJOTutorial -Dar
tifactId=vendor.hotdog -Dversion=1.0.0 -DpackageName=org.apache.felix.ipojo.example.vendor.hotdog

(2)实现vendor服务
HotDogVendor类实现了Vendor接口服务。服务的实现使用了bun service和wiener service。代码如下:
public class HotDogVendor implements Vendor {

/**
* Bun provider (required service).
*/
private Bun bunProvider;

/**
* Wiener provider (required service).
*/
private Wiener wienerProvider;

/**
* Sell method.
* To provide an hotdog, the vendor consume a bun and a wiener.
* This method is synchronized to avoid serving to client
* at the same time.
* @return a hotdog.
* @see org.apache.felix.ipojo.example.vendor.service.Vendor#sell()
*/
public synchronized Product sell() {
bunProvider.getBun();
wienerProvider.getWiener();
return new HotDog();
}
}


代码实现后,我们需要来描述组件的类型。metadata.xml包含了iPOJO 组件的描述信息:
<ipojo>
<component
classname="org.apache.felix.ipojo.example.vendor.hotdog.HotDogVendor"
name="HD" public-factory="false">
<provides/>
<requires field="bunProvider"/>
<requires field="wienerProvider"/>
</component>

<instance component="HD"/>
</ipojo>


组件定义一个输出服务(vendor服务)。因此,组件定义了2个服务依赖(使用"requiress")。你知道,我们的样例中有2个vendor,我们企望能增加一些对服务的描述——服务属性。为了完成这一个任务,我们仅需在provids标签中增加一些信息:

<ipojo>
<component
classname="org.apache.felix.ipojo.example.vendor.hotdog.HotDogVendor"
name="HD" public-factory="false">
<provides>
<property name="product" type="string" value="hotdog"/>
</provides>
<requires field="bunProvider"/>
<requires field="wienerProvider"/>
</component>

<instance component="HD"/>
</ipojo>

服务属性非常的重要,比如通过一些服务属性标志,就可以被其他框架级别的bundle侦测到,然后做一些处理。如发布为webservice。


publishing 'dynamic'属性
bun服务和wiener服务同样可以暴露服务属性。在我们的案例中,这些服务属性用于描述库存。
服务每使用一次,属性值就被修改一次。
public class BunWienerProvider implements BunService, WienerService {

private int bunStock;

private int wienerStock;

public synchronized void getBun() {
bunStock = bunStock - 1;
}

public synchronized void getWiener() {
wienerStock = wienerStock - 1;
}
}


库存信息的访问是同步的,避免同一时间多个访问修改值。组件类型metadata必须相应地定义为:

<ipojo>
<component
classname="org.apache.felix.ipojo.example.vendor.provider.BunProvider"
name="buns_and_wieners" public-factory="false">
<provides>
<property name="buns" field="bunStock" value="10"/>
<property name="wieners" field="wienerStock" value="10"/>
</provides>
</component>

<instance component="buns_and_wieners"/>
</ipojo>

在“provides”元素中,增加了2个属性。在property中包含了一个"field"属性,用于将服务属性和实现类的字段关联起来。因此默认值就是value的值。在代码中,属性字段将包含一个初始值10.因此每当字段被修改,服务属性就会被更新。注意iPOJO支持方法注入属性。


配置实例
在上面的例子中,属性被配置在组件描述中。它也可以在实例中自定义任何的属性。按此方法,每个实例可以包含不同的值。

<ipojo>
<component
classname="org.apache.felix.ipojo.example.vendor.provider.BunProvider"
name="buns_and_wieners" public-factory="false">
<provides>
<property name="buns" field="bunStock" value="10"/>
<property name="wieners" field="wienerStock" value="10"/>
</provides>
</component>

<instance component="buns_and_wieners">
<property name="buns" value="9"/>
<property name="wieners" value="8"/>
</instance>
</ipojo>


上面的metadata演示了在实例中发布配置。实例声明包含了2个property元素。实例配置可以覆盖组件中的初始值。属性默认是可选项,这就意味着它们无需要接收值。在本例中,默认值和java中的默认字段值是一致的(如,boolean:false int:0 double:0.0)。


在服务请求中使用过滤表达式
现在,bun和wiener供应者公布了它们的库存。热狗商可以查询库存不为空的bun和winener服务。要想做到这一点,我们必须定义LDAP风格的过滤表达式。接下来的XML片断显示如下:
<ipojo>
<component
classname="org.apache.felix.ipojo.example.vendor.hotdog.HotDogVendor"
name="HD" public-factory="false">
<provides>
<property name="product" type="string" value="hotdog"/>
</provides>
<requires field="bunProvider" filter="(buns>=1)"/>
<requires field="wienerProvider" filter="(wieners>=1)"/>
</component>

<instance component="HD"/>
</ipojo>

当服务供应者不符合LDAP过滤条件时,那么此供应者就不再被使用,并且跟踪其他符合条件的。如果,没有供应者来满足约束条件,那么实例将变为invalid并且等待等待一个适合的供应者。


Instance invalidation and services
When an instance becomes invalid, all its provided services are withdrawn from the service registry. So, this instance is no more _accessible_ from the service registry.


Immediate component instance
现在我们得到了热狗供应者。我们接下来实现customers。Customers在vendor.customer项目中实现。一个customer只是简单地查找商家,并购买想要的食品。


public class Customer {

private VendorService vendor;

private String name;

public Customer() {
System.out.println("Customer " + name + " bought "
+ vendor.sell() + " from " + vendor.getName());
}


}

上面的代码展示了customer的一种可能实现。然而,"sell"方法被载构造方法中调用,而构造方法仅只能在类对象被创建后。使用iPOJO存在2种方法激活一个实例一旦它的状态变成为valid。

第一种方法是用声明周期回调。第二种方法通过将组件定义为即时组件(immediate)。一个即时组件实例会在它变成valid时创建一个它的实现类对象。
<ipojo>
<component
classname="org.apache.felix.ipojo.example.vendor.customer.Customer"
name="customer" immediate="true">
<requires field="vendor"/>
<properties>
<property field="name"/>
</properties>
</component>
</ipojo>

把组件声明为immediate很简单,在component描述中增加属性immediate="true"即可。因此,一旦vendor服务变得可用,对象就被创建了。此外,该类型声明了一个属性(将name传递给customers)。这个属性不是服务属性,仅仅是内部属性。至于服务属性,在实例创建时,name字段将会被一个值注入。

默认情况下,所有不提供服务的组件都是immediate。其他组件则是在第一次被使用时,创建并调用构造方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值