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。其他组件则是在第一次被使用时,创建并调用构造方法。

你可能感兴趣的:(apache,xml,项目管理,配置管理,osgi)