I found the link for JSTL integration on the Wiki:

http://wiki.opensymphony.com/space/Using+JSTL+seamlessly+with+WebWork

One problem with the approach is that if an _expression_ string happened to match a value out of the request attributes, it could cause you some headaches.  So I came up with an alternate approach.  It requires adding a small method to an existing Apache JSTL class, and adds 2 small classes to Webwork.  First we add the following method to ExpressionEvaluatorManager in the JSTL (the doc says the class was designed as a plug point, but was obviously never finished):

   /**
    * Enhancement to allow plugging in alternate _expression_ engines.
    * @param expressionEvaluator
    */
   public static void installExpressionEvaluator( ExpressionEvaluator expressionEvaluator )
   {
      nameMap.put( EVALUATOR_CLASS, expressionEvaluator );
   }

If anyone who reads this is a commiter on the JSTL project, it would be fabulous if you could add this method.  You could make it more generic and not use the FQCN of the Evaluator class as the key to the map, but that is more an issue of elegance.  On the Webwork side, we add a ServletContextListener that calls the above method to install our own _expression_ evaluator:

package com.multideck.webwork;

import javax.servlet.ServletContextListener;
import javax.servlet.ServletContextEvent;

import org.apache.taglibs.standard.lang.support.ExpressionEvaluatorManager;


/**
 * <p>Installs an ExpressionEvaluator into the ServletContext to be used by the
 * Apache Jakarta JSTL implementation.  Specifically, the
 * ExpressionEvaluatorManager is setup to look in the ServletContext for an
 * installed ExpressionEvaluator interface.  If one does not exist, then it
 * defaults to using its built in EL interpreter.  Of course the Apache JSTL
 * has to be in the path for this listener to execute properly.</p>
 *
 * File Creation Date: Oct 15, 2003<br>
 * <br>
 * Copyright @2003 Multideck Corporation<br>
 * All rights reserved.<br>
 * @author <a href=''"><[EMAIL PROTECTED]'>Frederick N. Brier</a>
 * @version $Revision: 1.0 $
 */
public class JstlWebworkSupportListener implements ServletContextListener
{
   /**
    * Call the new installExpressionEvaluator() method on the enhanced
    * ExpressionEvaluatorManager class passing an instance of the
    * WebworkExpressionEvaluator class that implements the ExpressionEvaluator
    * interface.
    * @param event
    */
   public void contextInitialized( ServletContextEvent event )
   {
      WebworkExpressionEvaluator evaluator = new WebworkExpressionEvaluator();
      ExpressionEvaluatorManager.installExpressionEvaluator( evaluator );
   }

   /**
    * Do nothing.
    * @param event
    */
   public void contextDestroyed( ServletContextEvent event )
   {
   }
}

And finally we have the OGNL Webwork evaluator itself that implements the Jakarta JSTL ExpressionEvaluator interface:

package com.multideck.webwork;

import javax.servlet.jsp.tagext.Tag;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.JspException;

import org.apache.taglibs.standard.lang.support.ExpressionEvaluator;

import com.opensymphony.xwork.ActionContext;
import com.opensymphony.xwork.util.OgnlValueStack;


/**
 * <p>Jakarta JSTL ExpressionEvaluator implementation that utilizes the Webwork2
 * ActionContext OGNL valueStack instead of EL.</p>
 *
 * File Creation Date: Oct 15, 2003<br>
 * <br>
 * Copyright @2003 Multideck Corporation<br>
 * All rights reserved.<br>
 * @author <a href=''"><[EMAIL PROTECTED]'>Frederick N. Brier</a>
 * @version $Revision: 1.0 $
 */
public class WebworkExpressionEvaluator implements ExpressionEvaluator
{
   public WebworkExpressionEvaluator()
   {
   }


   /**
    * Translation time validation of an _expression_.
    * This method will return a null String if the _expression_
    * is valid; otherwise an error message.
    */
   public String validate( String attributeName,
                           String _expression_ )
   {
      // Todo: Figure out if OGNL has a validator to use here.
      return null;
   }


   /**
    * Evaluates the _expression_ at request time.
    * @param attributeName - used for logging.
    * @param _expression_
    * @param expectedType
    * @param tag - used for logging.
    * @param pageContext - not needed unless we decide to populate the valueStack with additional maps such as
    * request, response, session, pageContext, etc.
    * @return
    * @throws JspException
    */
   public Object evaluate( String attributeName,
                           String _expression_,
                           Class expectedType,
                           Tag tag,
                           PageContext pageContext )
         throws JspException
   {
      OgnlValueStack valueStack = ActionContext.getContext().getValueStack();
      return valueStack.findValue( _expression_, expectedType );
   }
}

To use JSTL all we need in our web.xml is a listener declaration:

<listener>
    <listener-class>com.multideck.webwork.JstlWebworkSupportListener</listener-class>
</listener>

If you choose to add this to the codebase, please feel free to put the classes in an appropriate Webwork2 package, and remove the copyright notice.  It is my company, my code.  I have tested this inside a Webwork2 iterator tag which was iterating over an Action class property.  A JSTL <fmt:formatDate> tag accessed the current element being iterated over and it works great.  Also if this is an acceptable approach, we probably need to make an enhancement request to the Jakarta JSTL team.

Frederick N. Brier
President
Multideck Corporation













Reply via email to