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

来源:互联网 发布:知其所以然前面一句 编辑:程序博客网 时间:2024/05/01 06:44

(转载自: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 


原创粉丝点击