jsr341-experts@el-spec.java.net

[jsr341-experts] Local bean repository

From: Kin-man Chung <kinman.chung_at_oracle.com>
Date: Tue, 16 Aug 2011 16:42:39 -0700

After my mail to Mark, discussing doing things that should be done in
Java rather than in EL, I suddenly realize that we need a local
repository to define beans that can be used in EL expressions. So I
added a local bean repository that an user can deposit beans, and added
a new method for he/she to do so.

Example:

     elProcessor.defineBean("curDate", new Date()); // Define curDate
to be a Date
     elProcessor.getValue("#{curDate.year}"); // and use it in another
expression
     elProcessor.defineBean("curDate", null); // remove it after use;

With this, I actually have weaken my case for the need to have EL
constructors! :-)

If there is no objections, I'll make the following change.

misto:el%svn diff
Index: StandardELContext.java
===================================================================
--- StandardELContext.java (revision 4)
+++ StandardELContext.java (working copy)
@@ -1,6 +1,7 @@
  package javax.el;

-import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
  import java.lang.reflect.Method;

  /*
@@ -45,6 +46,11 @@
      private ELContext delegate = null;

      /**
+ * A bean repository local to this context
+ */
+ private Map<String, Object> beans = new ConcurrentHashMap<String,
Object>();
+
+ /**
       * Default Constructor
       */
      public StandardELContext() {
@@ -90,6 +96,7 @@
      public ELResolver getELResolver() {
          if (elResolver == null) {
              CompositeELResolver resolver = new CompositeELResolver();
+ resolver.add(new BeanNameELResolver(new
LocalBeanNameResolver()));
              resolver.add(new MapELResolver());
              resolver.add(new ResourceBundleELResolver());
              resolver.add(new ListELResolver());
@@ -131,6 +138,14 @@
      }

      /**
+ * Get the local bean repository
+ * @return the bean repository
+ */
+ public Map<String, Object> getBeans() {
+ return beans;
+ }
+
+ /**
       * Construct (if needed) and return a default FunctionMapper.
       * @param The default FunctionMapper
       */
@@ -156,7 +171,7 @@

      private static class DefaultFunctionMapper extends FunctionMapper {

- private HashMap<String, Method> functions = null;
+ private Map<String, Method> functions = null;

          @Override
          public Method resolveFunction(String prefix, String localName) {
@@ -170,7 +185,7 @@
          @Override
          public void mapFunction(String prefix, String localName,
Method meth){
              if (functions == null) {
- functions = new HashMap<String, Method>();
+ functions = new ConcurrentHashMap<String, Method>();
              }
              functions.put(prefix + ":" + localName, meth);
          }
@@ -178,7 +193,7 @@

      private static class DefaultVariableMapper extends VariableMapper {

- private HashMap<String, ValueExpression> variables = null;
+ private Map<String, ValueExpression> variables = null;

          @Override
          public ValueExpression resolveVariable (String variable) {
@@ -190,16 +205,36 @@

          @Override
          public ValueExpression setVariable(String variable,
- ValueExpression expression) {
+ ValueExpression expression) {
+ if (variables == null) {
+ variables = new ConcurrentHashMap<String,
ValueExpression>();
+ }
              ValueExpression prev = null;
              if (expression == null) {
- variables.remove(variable);
+ prev = variables.remove(variable);
              } else {
- prev = variables.get(variable);
- variables.put(variable, expression);
+ prev = variables.put(variable, expression);
              }
              return prev;
          }
      }
+
+ private class LocalBeanNameResolver extends BeanNameResolver {
+
+ @Override
+ public String getBean(String beanName) {
+ return beans.get(beanName);
+ }
+
+ @Override
+ public void setBeanValue(String beanName, Object value) {
+ beans.set(beanName, value);
+ }
+
+ @Override
+ public boolean isReadOnly(String beanName) {
+ return false;
+ }
+ }
  }

Index: ELProcessor.java
===================================================================
--- ELProcessor.java (revision 3)
+++ ELProcessor.java (working copy)
@@ -131,5 +131,14 @@
          }
          elManager.mapFunction(prefix, localName, meth);
      }
+
+ /**
+ * Define a bean in a local bean repository
+ * @name The name of the bean
+ * @bean The bean instance to be defined
+ */
+ public void defineBean(String name, Object bean) {
+ elManage.defineBean(name, bean);
+ }
  }

Index: ELManager.java
===================================================================
--- ELManager.java (revision 4)
+++ ELManager.java (working copy)
@@ -102,8 +102,6 @@
       * @param variable The variable name
       * @param expression The ValueExpression to be assigned
       * to the variable.
- * @return The previous ValueExpression assigned to this variable,
- * null if there is no previouse assignment to this variable.
       */
      public void setVariable(String variable, ValueExpression expression) {
          getELContext().getVariableMapper().setVariable(variable,
expression);
@@ -126,4 +124,12 @@
          getELContext().getImportHandler().importPackage(packageName);
      }

+ /**
+ * Define a bean in the local bean repository
+ * @name The name of the bean
+ * @bean The bean instance to be defined
+ */
+ public void defineBean(String name, Object bean) {
+ getELContext().getBeans().set(name, bean);
+ }
  }