如何在Table组件中使用Active Data Service?

来源:互联网 发布:禁用445端口 编辑:程序博客网 时间:2024/05/18 02:48
运行环境:JDeveloper 11.1.2.2.0 + Oracle Database 10g Express Edition 10.2.0.1。

Active Data Service是ADF中的一个高级特性,本文介绍如何在Table中使用ADS。

重点步骤说明:

1. 页面代码
<af:table value="#{stockManager}" var="row" rowBandingInterval="0" id="t1">    <af:column sortable="false" headerText="Ticket" align="start" id="c1">        <af:outputText value="#{row.ticket}" id="ot1"/>    </af:column>    <af:column sortable="false" headerText="Value" align="start" id="c2">        <af:outputText value="#{row.value}" id="ot2"/>    </af:column></af:table>

说明:Table的value属性绑定到一个Managed Bean。

2. adfc-config.xml
<managed-bean id="__1">  <managed-bean-name>stockManager</managed-bean-name>  <managed-bean-class>view.StockManager</managed-bean-class>  <managed-bean-scope>session</managed-bean-scope></managed-bean><managed-bean id="__2">  <managed-bean-name>stockBackend</managed-bean-name>  <managed-bean-class>view.StockBackEnd</managed-bean-class>  <managed-bean-scope>session</managed-bean-scope>  <managed-property>    <property-name>listener</property-name>    <value>#{stockManager}</value>  </managed-property></managed-bean>

说明:注册Managed Bean:StockManager和StockBackEnd。
其中,StockBackEnd有一个属性:listener,指向StockManager。

3. 完整的StoreManager的代码
package view;import javax.el.ExpressionFactory;import javax.el.ValueExpression;import javax.faces.context.FacesContext;import oracle.adf.view.rich.activedata.ActiveDataEventUtil;import oracle.adf.view.rich.event.ActiveDataEntry;import oracle.adf.view.rich.event.ActiveDataUpdateEvent;import oracle.adf.view.rich.model.ActiveCollectionModelDecorator;import oracle.adf.view.rich.model.ActiveDataModel;import org.apache.myfaces.trinidad.model.CollectionModel;import org.apache.myfaces.trinidad.model.SortableModel;public class StockManager extends ActiveCollectionModelDecorator implements IBackendListener {    @Override    public ActiveDataModel getActiveDataModel() {        return stockModel;    }    @Override    protected CollectionModel getCollectionModel() {        if (collectionModel == null) {            FacesContext ctx = FacesContext.getCurrentInstance();            ExpressionFactory ef = ctx.getApplication().getExpressionFactory();            ValueExpression ve = ef.createValueExpression(ctx.getELContext(), "#{stockBackend}", StockBackEnd.class);            StockBackEnd context = (StockBackEnd)ve.getValue(ctx.getELContext());            collectionModel = new SortableModel(context.getStocks());        }        return collectionModel;        //        if (collectionModel == null) {        //            // connect to a backend system to get a Collection        //            List stocks = FacesUtil.loadBackEnd().getStocks();        //            // make the collection become a (Trinidad) CollectionModel        //            collectionModel = new SortableModel(stocks);        //        }        //        return collectionModel;    }    /**     * Callback from the backend to push new data to our decorator.     * The decorator itself notifies the ADS system that there was a data change.     *     * @param key the rowKey of the updated Stock     * @param updatedStock the updated stock object     */    @Override    public void onStockUpdate(Integer rowKey, Stock stock) {        if (rowKey != null) {            System.out.println("Stock " + stock.getTicket() + " Changed is : " +  stock.getValue() );            ActiveStockModel asm = getActiveStockModel();            asm.prepareDataChange();            ActiveDataUpdateEvent event =                ActiveDataEventUtil.buildActiveDataUpdateEvent(ActiveDataEntry.ChangeType.UPDATE,                                                               asm.getCurrentChangeCount(), new Object[] { rowKey },                                                               null, new String[] { "value" },                                                               new Object[] { stock.getValue() });            // Deliver the new Event object to the ADS framework            asm.notifyDataChange(event);        }    }    /**     * Typesafe caller for getActiveDataModel()     * @return     */    protected ActiveStockModel getActiveStockModel() {        return (ActiveStockModel)getActiveDataModel();    }    private CollectionModel collectionModel;    private ActiveStockModel stockModel = new ActiveStockModel();}

说明:
(1)StockManager继承了ActiveCollectionModelDecorator,重写了方法getCollectionModel,该方法返回集合对象。这里使用了ValueExpression动态绑定到StockBackEnd,这样不用自己构造CollectionModel对象。
(2)StockManager实现了IBackendListener接口,重写了方法onStockUpdate,该方法向ADS framework发送UpdateEvent。

4. 完整的StockBackEnd的代码
package view;import java.util.List;import java.util.concurrent.CopyOnWriteArrayList;import javax.annotation.PostConstruct;import javax.annotation.PreDestroy;public class StockBackEnd {    public StockBackEnd() {        stocks.add(new Stock("中国联通", 1.0));        stocks.add(new Stock("中国石油", 2.0));        stocks.add(new Stock("盐湖钾肥", 3.0));    }    public void setListener(IBackendListener listener) {        this.listener = listener;    }    public IBackendListener getListener() {        return listener;    }    private IBackendListener listener;    private final List<Stock> stocks = new CopyOnWriteArrayList<Stock>();    public List<Stock> getStocks() {        return stocks;    }    public void changeData() {        List<Stock> rows = getStocks();        Stock dataRow = null;        for (int rowKey = 0; rowKey < rows.size(); rowKey++) {            dataRow = rows.get(rowKey);            dataRow.setValue(dataRow.getValue() + 1.0);            listener.onStockUpdate(rowKey, dataRow);            Long stoptime = 2000L;            try {                Thread.sleep(stoptime);            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }    @PostConstruct    private void startUpdateProcess() {        Runnable dataChanger = new Runnable() {            public void run() {                // wait 10 seconds before we start to update our stocks...                try {                    Thread.sleep(10000);                } catch (InterruptedException e) {                    throw new RuntimeException(e);                }                while (listener != null) {                    try {                        Thread.sleep(3000);                        changeData();                    } catch (InterruptedException e) {                        throw new RuntimeException(e);                    }                }            }        };        Thread newThread = new Thread(dataChanger);        newThread.start();    }    @PreDestroy    private void stopUpdateProcess() {        if (listener != null) {            System.out.println("listener " + listener);            listener = null;        }    }}

说明:
(1)StockBackEnd定义了数据源,实际情况中,你应该在这里重新定义你获取数据的方式。
(2)StockBackEnd定义了触发ChangeData的方式:这里是在执行完毕构造函数后,启动一个线程,每隔10秒,执行一次ChangeData方法。
实际情况中,你应该在这里重新定义触发方式,比如使用JMS。

6. 完整的ActiveStockModel的代码
package view;import java.util.Collection;import java.util.concurrent.atomic.AtomicInteger;import oracle.adf.view.rich.activedata.BaseActiveDataModel;import oracle.adf.view.rich.event.ActiveDataUpdateEvent;public class ActiveStockModel extends BaseActiveDataModel {    @Override    protected void startActiveData(Collection<Object> rowKeys, int startChangeCount) {    }    @Override    protected void stopActiveData(Collection<Object> rowKeys) {    }    @Override    public int getCurrentChangeCount() {        return changeCounter.get();    }    /**     * Increment the change counter.     */    public void prepareDataChange() {        changeCounter.incrementAndGet();    }    /**     * Deliver an ActiveDataUpdateEvent object to the ADS framework.     *     * @param event the ActiveDataUpdateEvent object     */    public void notifyDataChange(ActiveDataUpdateEvent event) {        fireActiveDataUpdate(event);    }    private final AtomicInteger changeCounter = new AtomicInteger();}

说明:该类的作用是把ActiveDataUpdateEvent对象发送给ADS framework。

7. 运行效果
每行数据依次被更新(背景色显示为蓝色),而整个Table并没有被刷新。


Project 下载:ADF_ADS_Table.7z

参考文献:
1.《Web User Interface Developer’s Guide for ADF》之 Using the Active Data Service with an Asynchronous Backend
2.《Fusion Developer's Guide for ADF》之 Using the Active Data Service
3. http://biemond.blogspot.com/2009/12/adf-data-push-with-active-data-service.html
4. http://matthiaswessendorf.wordpress.com/2010/01/07/adf%E2%80%99s-active-data-service-and-scalar-data-like-activeoutputtext/
5. http://matthiaswessendorf.wordpress.com/2009/12/05/adf-faces-and-server-side-push/
6. http://matthiaswessendorf.wordpress.com/2009/12/11/adfs-active-data-service-and-multiple-push-windows/

7. http://technology.amis.nl/2011/10/19/adf-faces-handle-task-in-background-process-and-show-real-time-progress-indicator-for-asynchronous-job-using-server-push-in-adf/

http://maping930883.blogspot.com/2012/07/adf173tableactive-data-service.html

0 0