cocoon-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Daniel Fagerstrom <dani...@nada.kth.se>
Subject [RFC] Plugable Expressions
Date Mon, 17 Jan 2005 10:37:27 GMT
I have implemented a first version of plugable expressions as discussed 
in: http://marc.theaimsgroup.com/?t=109903957300001&r=1&w=2 and the end 
of http://marc.theaimsgroup.com/?t=109901879000001&r=1&w=2. I use them 
in the refactored JXTG but in a way that (hopefully) is completely 
invisible for the user.

I would like to get your feedback on the approach, intefaces, 
implementation etc. So that we can improve it and move it to the core as 
a standard interface for expression usage when it is good enough.

Src
===

The code can be found in (in trunk):
  
src/blocks/template/java/org/apache/cocoon/components/expression/expression
tests in:
  
src/blocks/template/test/org/apache/cocoon/components/expression/expression

A FOM like context (slight modification of TemplateObjectHelper in 
scratchpad):
  src/blocks/template/java/org/apache/cocoon/environment/environment
And some test:
  src/blocks/template/test/org/apache/cocoon/environment/environment

Background
==========

Expression languages (EL), mainly JXPath and Jexl are used in various 
parts of Cocoon, e.g. in JXTG, CForms, various input modules etc. The 
ELs often are used on some kind of Cocoon object model. It would be 
easier to use Coocoon if expressions would be used in the same way 
everywhere in Cocoon and it would simplify maintainance if there was 
just one implementation.

Couldn't we just decide to use one EL everywhere? This has been 
discussed in the threads cited above. While most people would prefer 
having just one EL we could not agree on which one. Also JXPath makes 
much more sense on DOM and Jexl on Java beans.

Design
======

The design this far has some focus on my needs for using it in JXTG. It 
is inspired by JEX written Dmitri Plotnikov (JXPaths main author) 
http://cvs.apache.org/viewcvs.cgi/jakarta-commons-sandbox/jex/ and 
http://www.plotnix.com/jex/index.html. As JEX just consists of a two 
year old initial code base and doesn't support Jexl, I thought that it 
was better to build our own stuff. Compared to JEX my design is simpler. 
There is e.g. no locale support as that IMO should be handled by a 
separate convertor component. And I have not differed between compiled 
and interpreted expressions.

ExpressionContext
-----------------

To make it possible to use several ELs at the same time as in JXTG there 
is one concrete ExpressionContext class that are used by all ELs. It is 
a Map of variable bindings but also has a contextBean property and 
supports parent contexts. ExpressionContext is similar to JexlContext, 
not because I found it especialy elegant (I don't), but rather because 
the needs from Jexl constrained the design a bit if I wanted to avoid to 
much work in the adapter, (better designs are certainly welcome).

Also the ExpressionContext is only a data object. In JXPath there are a 
set of "evaluate expression" etc methods on the context but I preferd to 
focus on the "CompiledExpression" scenario needed for JXTG furthermore I 
don't like having two ways of acchieving about the same thing.

ExpressionFactory
-----------------

The expression factory is modeled after the SourceResolver. Typical use is:

  ExpressionFactory factory = 
(ExpressionFactory)this.lookup(ExpressionFactory.ROLE);
  ExpressionContext context = new ExpressionContext());
  context.put("a", new Float(1));
  context.put("b", new Float(2));

  // Geting a Jexl expression
  Expression expression = factory.getExpression("jexl", "a+b");
  assertEquals(new Long(3), expression.evaluate(context));

  // Letting the EL be part of the expression string
  expression = factory.getExpression("jexl:a+b");
  assertEquals(new Long(3), expression.evaluate(context));

  expression = factory.getExpression("jxpath:$a+$b");
  assertEquals(new Double(3), expression.evaluate(context));

  // Using the default EL
  expression = factory.getExpression("$a+$b");
  assertEquals(new Double(3), expression.evaluate(context));

  this.release(factory);

The available ELs and the default EL are configured in the relevant 
*.xconf. I only used release on the factory object as I didn't found any 
use for that for Jexl and JXPath expressions.

Expression
----------

The Expression interface looks like:

public interface Expression {
    public Object evaluate(ExpressionContext context) throws 
ExpressionException;
    public Iterator iterate(ExpressionContext context) throws 
ExpressionException;
    public void assign(ExpressionContext context, Object value) throws 
ExpressionException;

    public String getExpression();
    public String getLanguage();

    public void setProperty(String property, Object value);
    public Object getNode(ExpressionContext context) throws 
ExpressionException;
}

evaluate, iterate and assign should be rather obvious. getExpression and 
getLanguage is mainly for making reasonable error messages possible.

I'm less certain about setProperty that I mainly added to be able to 
handle the lenient property for JXPath, but it is not certain that 
properties should be part of expressions, maybe they should be part of 
the factory instead.

I like the getNode method even less and would like to get rid of it. I 
introduced it as JXPath both has a getNode method that returns the raw 
object pointed to and a getValue that does some extra work on it, (like 
the irritating xsl:value-of stuff on DOM). Now Expression.evaluate 
basically does JXPath getValue and Expression.getNode does JXPath getNode.

I would prefer to get rid of the Expression.getNode method and have Let 
Expression.evaluate basically call JXPath getNode. But I don't know 
enough about the consequances for e.g. JXTG, any opinions?

JXPath and Jexl
---------------

I have implemented a JXPath and Jexl variant of the intefaces.

Questions
=========

* Is the design reasonable?
* Does it work for other ELs?
* Is it efficient enough? Especially considering ExpressionContext 
adaption and component lookup.
* What about getNode getValue in JXPath?
* The JXPathExpression contains some JXPath bug/inconvenience 
workorounds from JXTG, are they still needed, could they be fixed in JXPath?
* etc

/Daniel


Mime
View raw message