e4中的org.eclipse.e4.core.contexts.IContextFunction

轉載自:http://414149609.iteye.com/blog/1646251

這個實驗很有意思,簡單有效地證明了EclipseContext每次取一個值之前都會執行compute方法。實際e4 RCP開發過程中,常常結合Declarative Service來充分發揮e4的Dependency Injection的作用。簡單來說就是當一個類的構造函數有@inject的標籤,e4就會從EclipseContext裏面尋找符合的key,然後通過compute找出對象值,然後inject給構造函數。在Declarative Service中,把接口註冊在service.context.key屬性中,把實現類bind到 org.eclipse.e4.core.contexts.IContextFunction 服務,這樣一個標有inject的構造函數需要這個接口作爲變量時,e4會找到對應的實現類。這是e4的衆多美妙之處之一。


相信用過E4的EclipseContext的人都知道,EclipseContext是一個可以類似java的Map一樣存儲數據(key-value),而且EclipseContext還可以有父子關係,這裏不詳談。 


EclipseContext 存儲key-value的時候,這個value可以是動態變化的,也就是可以算出來的。這點跟java的map有很大差別。在java裏面一旦建立key和value的關係,除非對這個再進行put或者remove的操作,否則取出來的value都是同一個對象。而EclipseContext 提供了一個IContextFunction的接口,這個接口代碼如下: 


/******************************************************************************* 
 * Copyright (c) 2009, 2010 IBM Corporation and others. 
 * All rights reserved. This program and the accompanying materials 
 * are made available under the terms of the Eclipse Public License v1.0 
 * which accompanies this distribution, and is available at 
 * http://www.eclipse.org/legal/epl-v10.html 
 * 
 * Contributors: 
 *     IBM Corporation - initial API and implementation 
 *******************************************************************************/  
  
package org.eclipse.e4.core.contexts;  
  
import org.osgi.framework.BundleContext;  
  
/** 
 * A context function encapsulates evaluation of some code within an 
 * {@link IEclipseContext}. The result of the function must be derived purely 
 * from the provided arguments and context objects, and must be free from 
 * side-effects other than the function's return value. In particular, the 
 * function must be idempotent - subsequent invocations of the same function 
 * with the same inputs must produce the same result. 
 * <p> 
 * A common use for context functions is as a place holder for an object that 
 * has not yet been created. These place holders can be stored as values in an 
 * {@link IEclipseContext}, allowing the concrete value they represent to be 
 * computed lazily only when requested. 
 * </p> 
 * <p> 
 * Context functions can optionally be registered as OSGi services. Context 
 * implementations may use such registered services to seed context instances 
 * with initial values. Registering your context function as a service is a 
 * signal that contexts are free to add an instance of your function to their 
 * context automatically, using the key specified by the 
 * {@link #SERVICE_CONTEXT_KEY} service property. 
 * </p> 
 *  
 * @see IEclipseContext#set(String, Object) 
 * @noimplement This interface is not intended to be implemented by clients. 
 *              Function implementations must subclass {@link ContextFunction} 
 *              instead. 
 */  
public interface IContextFunction {  
    /** 
     * The OSGi service name for a context function service. This name can be 
     * used to obtain instances of the service. 
     *  
     * @see BundleContext#getServiceReference(String) 
     */  
    public static final String SERVICE_NAME = IContextFunction.class.getName();  
  
    /** 
     * An OSGi service property used to indicate the context key this function 
     * should be registered in. 
     *  
     * @see BundleContext#getServiceReference(String) 
     */  
    public static final String SERVICE_CONTEXT_KEY = "service.context.key"; //$NON-NLS-1$  
  
    /** 
     * Evaluates the function based on the provided arguments and context to 
     * produce a consistent result. 
     *  
     * @param context 
     *            The context in which to perform the value computation. 
     * @return The concrete value. 
     */  
    public Object compute(IEclipseContext context);  
  
}  

下面代碼演示一個使用ContextFunction的簡單例子,Jone每隔一段時間去檢查一下這個key爲"WEATHER"的value,每過一段時間會返回不一樣的天氣

package teste4;  
  
import java.util.Random;  
  
import org.eclipse.e4.core.contexts.ContextFunction;  
import org.eclipse.e4.core.contexts.EclipseContextFactory;  
import org.eclipse.e4.core.contexts.IEclipseContext;  
import org.eclipse.e4.core.internal.contexts.ContextChangeEvent;  
import org.eclipse.e4.core.internal.contexts.EclipseContext;  
import org.eclipse.equinox.app.IApplication;  
import org.eclipse.equinox.app.IApplicationContext;  
  
/** 
 * This class controls all aspects of the application's execution 
 */  
public class Application implements IApplication {  
  
    EclipseContext ec = null;  
    public static String weather = "sunshine";  
  
    public Object start(IApplicationContext context) throws Exception {  
        System.out.println("Hello RCP World!");  
        // System.out.println(context);  
        ec = (EclipseContext) EclipseContextFactory.create("root");  
        ec.set("WEATHER", new ContextFunction() {  
            public Object compute(final IEclipseContext context) {  
                return weather;  
            }  
        });  
        Thread thread1 = new Thread(Jone);  
        Thread thread2 = new Thread(WeatherReport);  
        thread1.setName("Jone");  
        thread1.start();  
        thread2.start();  
        return IApplication.EXIT_OK;  
    }  
  
    Runnable Jone = new Runnable() {  
  
        public void run() {  
            // 每過0.25秒檢查當前的天氣  
            while (true) {  
                try {  
                    Thread.sleep(250);  
                } catch (InterruptedException e) {  
                    e.printStackTrace();  
                }  
                System.out.println(checkWeather());  
  
            }  
        }  
  
        String checkWeather() {  
            return (String) ec.get("WEATHER");  
        }  
    };  
  
    Runnable WeatherReport = new Runnable() {  
        Random r = new Random(5);  
  
        @Override  
        public void run() {  
            // 每過0.5秒,更新一個天氣  
            while (true) {  
                switch (r.nextInt(5)) {  
                case 1:  
                    weather = "sunshine";  
                    break;  
                case 2:  
                    weather = "cloudy";  
                    break;  
                case 3:  
                    weather = "rainy";  
                    break;  
                case 4:  
                    weather = "windy";  
                    break;  
                default:  
                    weather = "very bad";  
                    break;  
                }  
                // /告訴要重新執行一次key="WEATHER" 對應的ContextFunction的compute方法  
                ec.invalidate("WEATHER", ContextChangeEvent.UPDATE, "", null);  
  
                try {  
                    Thread.sleep(500);  
                } catch (InterruptedException e) {  
                    e.printStackTrace();  
                }  
            }  
        }  
    };  
  
    public void stop() {  
    }  
}  

輸出如下: 
Hello RCP World! 
cloudy 
cloudy 
cloudy 
cloudy 
windy 
windy 
windy 
sunshine 
sunshine 
sunshine 
very bad 
very bad 
windy 
sunshine 
sunshine 
sunshine 
cloudy 
sunshine 
sunshine 
sunshine 
sunshine 
rainy 
rainy 
rainy 
cloudy 
very bad 
very bad 
very bad 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章