You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by ha...@apache.org on 2002/11/17 19:00:08 UTC

cvs commit: xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/components/language/markup/xsp/java esql.xsl

haul        2002/11/17 10:00:04

  Modified:    .        changes.xml
               src/java/org/apache/cocoon/transformation
                        SimpleFormTransformer.java
               src/java/org/apache/cocoon/components/modules modules.xconf
               src/java/org/apache/cocoon/components/modules/input
                        AbstractJXPathModule.java AbstractMetaModule.java
                        ChainMetaModule.java DateMetaInputModule.java
                        DefaultsMetaModule.java DigestMetaModule.java
                        MapMetaModule.java XMLMetaModule.java
               src/blocks/databases/java/org/apache/cocoon/components/modules/input
                        CollectionMetaModule.java
               src/blocks/databases/java/org/apache/cocoon/components/language/markup/xsp
                        EsqlHelper.java
               src/blocks/databases/java/org/apache/cocoon/components/language/markup/xsp/java
                        esql.xsl
  Added:       src/java/org/apache/cocoon/components/modules/input
                        JXPathMetaModule.java
  Log:
    <action dev="CH" type="update">
     Changed SimpleFormTransformer to use InputModules.
    </action>
    <action dev="CH" type="update">
     Changed InputModules to return Iterator instead of Enumeration. New abstract
     "meta" module to make new meta modules easier. Stripped "meta" from defaults
     module. Added JXPathMetaModule. Added extension classes and packages to all
     modules that are based on JXPath.
    </action>
  
  Revision  Changes    Path
  1.283     +10 -1     xml-cocoon2/changes.xml
  
  Index: changes.xml
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/changes.xml,v
  retrieving revision 1.282
  retrieving revision 1.283
  diff -u -r1.282 -r1.283
  --- changes.xml	14 Nov 2002 15:43:28 -0000	1.282
  +++ changes.xml	17 Nov 2002 18:00:02 -0000	1.283
  @@ -40,6 +40,15 @@
    </devs>
   
    <release version="@version@" date="@date@">
  +  <action dev="CH" type="update">
  +   Changed SimpleFormTransformer to use InputModules.
  +  </action>  
  +  <action dev="CH" type="update">
  +   Changed InputModules to return Iterator instead of Enumeration. New abstract
  +   "meta" module to make new meta modules easier. Stripped "meta" from defaults
  +   module. Added JXPathMetaModule. Added extension classes and packages to all 
  +   modules that are based on JXPath.
  +  </action>  
     <action dev="CZ" type="fix" fixes-bug="14466" due-to="Luca Morandini" due-to-email="lmorandini@ieee.org">
      Fixing namespace handling of SQLTransformer.
     </action>
  
  
  
  1.2       +197 -43   xml-cocoon2/src/java/org/apache/cocoon/transformation/SimpleFormTransformer.java
  
  Index: SimpleFormTransformer.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/java/org/apache/cocoon/transformation/SimpleFormTransformer.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- SimpleFormTransformer.java	9 Aug 2002 08:27:17 -0000	1.1
  +++ SimpleFormTransformer.java	17 Nov 2002 18:00:02 -0000	1.2
  @@ -52,17 +52,20 @@
   
   import org.apache.avalon.framework.component.ComponentException;
   import org.apache.avalon.framework.component.ComponentManager;
  +import org.apache.avalon.framework.component.ComponentSelector;
   import org.apache.avalon.framework.component.Composable;
   import org.apache.avalon.framework.parameters.Parameters;
   import org.apache.avalon.framework.configuration.Configurable;
   import org.apache.avalon.framework.configuration.Configuration;
   import org.apache.avalon.framework.configuration.ConfigurationException;
  +import org.apache.avalon.framework.thread.ThreadSafe;
   
   import org.apache.avalon.excalibur.pool.Recyclable;
   
   import org.apache.cocoon.ProcessingException;
   import org.apache.cocoon.acting.ValidatorActionResult;
   import org.apache.cocoon.components.language.markup.xsp.XSPFormValidatorHelper;
  +import org.apache.cocoon.components.modules.input.InputModule;
   import org.apache.cocoon.environment.ObjectModelHelper;
   import org.apache.cocoon.environment.Request;
   import org.apache.cocoon.environment.SourceResolver;
  @@ -81,9 +84,9 @@
    * Select options need a value attribute to work correctly.
    *
    * <p>This transformer fills all HTML 4 form elements with values from
  - * parameters of the request object with the same name. It handles
  - * select boxes, textareas, checkboxes, radio buttons, password and
  - * text fields, and buttons.</p>
  + * an InputModule, e.g. request, with the same name. It handles select
  + * boxes, textareas, checkboxes, radio buttons, password and text
  + * fields, and buttons.</p>
    *
    * <p>In addition, it handles FormValidatorAction results by
    * selectively omitting &lt;error/&gt; elements. These elements need a
  @@ -107,6 +110,22 @@
    *   &lt;map:transform type="simple-form"/&gt;
    * </pre></p>
    *
  + * <p>Configuration elements:
  + * <table>
  + *   <tr><td>input-module</td><td>(String) InputModule configuration, 
  + *           defaults to an empty configuration and the "request-param" module</td></tr>
  + * </table>
  + * </p>
  + *
  + * <p>Sitemap parameters:
  + * <table>
  + *   <tr><td>fixed</td><td>(boolean) Do not change values</td></tr>
  + *   <tr><td>prefix</td><td>(String) Added to the input element's name</td></tr>
  + *   <tr><td>postfix</td><td>(String) Added to the input element's name</td></tr>
  + *   <tr><td>input</td><td>(String) InputModule name</td></tr>
  + * </table>
  + * </p>
  + *
    * <p>Example:<pre>
    *     &lt;input name="user.name" size="50" maxlength="60"/&gt;
    *     &lt;error name="user.name" when-ge="error"&gt;required&lt;/error&gt;
  @@ -143,6 +162,8 @@
       /** default input type as Integer (needed as default in org.apache.cocoon.util.HashMap.get()) */
       private static final Integer defaultType = new Integer(TYPE_DEFAULT);
       
  +    protected static final String INPUT_MODULE_ROLE = InputModule.ROLE;
  +    protected static final String INPUT_MODULE_SELECTOR = INPUT_MODULE_ROLE+"Selector";
   
       /** map element name string to symbolic name */
       private static final HashMap elementNames;
  @@ -197,11 +218,8 @@
       /** stack of ignored element names */
       protected Stack   stack = new Stack();
   
  -    /** name attribute of current select element */
  -    protected String selectName = null;
  -
       /** current element's request parameter values */
  -    protected String[] values = null;
  +    protected Object[] values = null;
       
       /** current request's validation results (all validated elements) */
       protected Map validationResults = null;
  @@ -215,8 +233,19 @@
       /** The Avalon ComponentManager for getting Components */
       protected ComponentManager   manager;
   
  -    /** Are we already initialized for the current request? */
  -    private boolean isInitialized;
  +    /** Should we skip inserting values? */
  +    private boolean fixed = false;
  +
  +    private String prefix = null;
  +    private String postfix = null; 
  +
  +    private String defaultInput = "request-param";
  +    private Configuration defaultInputConf = null;
  +    private Configuration inputConf = null;
  +    private InputModule input = null;
  +    private ComponentSelector inputSelector = null;
  +    private String inputName = null;
  +
   
       /** Empty attributes (for performance). This can be used
        *  do create own attributes, but make sure to clean them
  @@ -231,17 +260,24 @@
           this.parameters = null;
           this.stack.clear();
           this.ignoreCount = 0;
  -        this.selectName = null;
           this.values = null;
           this.validationResults = null;
  +
  +        if (this.inputSelector != null) {
  +            if (this.input != null)
  +                this.inputSelector.release(this.input);
  +            this.manager.release(this.inputSelector);
  +        }
       }
   
   
       /**
        * Avalon Configurable Interface
        */
  -    public void configure(Configuration configuration)
  +    public void configure(Configuration config)
       throws ConfigurationException {
  +        this.defaultInputConf = config.getChild("input-module");
  +        this.defaultInput = this.defaultInputConf.getAttribute("name",this.defaultInput);
       }
   
   
  @@ -265,8 +301,46 @@
               throw new ProcessingException("no request object");
           }
           this.parameters = par;
  -        this.isInitialized = false;
  +        this.fixed = par.getParameterAsBoolean("fixed",false);
  +        this.prefix = par.getParameter("prefix",null);
  +        this.postfix = par.getParameter("postfix",null);
  +        this.inputName = par.getParameter("input",null);
  +        this.inputConf = null;
           this.validationResults = XSPFormValidatorHelper.getResults(objectModel);
  +
  +        if (this.inputName == null) {
  +            this.inputName = this.defaultInput;
  +            this.inputConf = this.defaultInputConf;
  +        }
  +        
  +        try {
  +            // obtain input module
  +            this.inputSelector=(ComponentSelector) this.manager.lookup(INPUT_MODULE_SELECTOR); 
  +            if (this.inputName != null && 
  +                this.inputSelector != null && 
  +                this.inputSelector.hasComponent(this.inputName)
  +                ){
  +                this.input = (InputModule) this.inputSelector.select(this.inputName);
  +                if (!(this.input instanceof ThreadSafe && this.inputSelector instanceof ThreadSafe) ) {
  +                    this.inputSelector.release(this.input);
  +                    this.manager.release(this.inputSelector);
  +                    this.input = null;
  +                    this.inputSelector = null;
  +                }
  +            } else {
  +                if (this.inputName != null)
  +                    if (getLogger().isErrorEnabled())
  +                        getLogger().error("A problem occurred setting up '" + this.inputName 
  +                                          +"': Selector is "+(this.inputSelector!=null?"not ":"")
  +                                          +"null, Component is "
  +                                          +(this.inputSelector!=null&&this.inputSelector.hasComponent(this.inputName)?"known":"unknown"));
  +            }
  +        } catch (Exception e) {
  +            if (getLogger().isWarnEnabled()) 
  +                getLogger().warn("A problem occurred setting up '" + this.inputName + "': " + e.getMessage());
  +        }
  +        
  +
       }
   
       /**
  @@ -307,17 +381,22 @@
       /**
        * Handle input elements that may have a "checked" attributes,
        * i.e. checkbox and radio.
  -     * @param aName name of input element from "name" attribute.
        */
  -    protected void startCheckableElement(String uri, String name, String raw, AttributesImpl attributes, String aName)
  +    protected void startCheckableElement(String uri, String name, String raw, AttributesImpl attributes)
           throws SAXException {
   
  +        // @fixed and this.fixed already considered in startInputElement
           String checked = attributes.getValue("checked");
           String value = attributes.getValue("value");
  -        if (aName != null){
  -            boolean found = false;
  +        boolean found = false;
  +                
  +        if (getLogger().isDebugEnabled())
  +            getLogger().debug("startCheckableElement "+name+" attributes "+this.printAttributes(attributes));
  +        if (this.values != null) {
  +            if (getLogger().isDebugEnabled())
  +                getLogger().debug("replacing");
               for (int i=0; i<this.values.length; i++) {
  -                if (this.values[i].equals(String.valueOf(value))) {
  +                if (this.values[i].equals(value)) {
                       found = true;
                       if (checked == null) {
                           attributes.addAttribute("","checked","checked","CDATA","");
  @@ -336,22 +415,24 @@
       /**
        * Handle input elements that may don't have a "checked"
        * attributes, e.g. text, password, button.
  -     * @param aName name of input element from "name" attribute.
        */
  -    protected void startNonCheckableElement(String uri, String name, String raw, AttributesImpl attributes, String aName)
  +    protected void startNonCheckableElement(String uri, String name, String raw, AttributesImpl attributes)
           throws SAXException {
   
  +        // @fixed and this.fixed already considered in startInputElement
           String value = attributes.getValue("value");
  -        this.values = (aName != null ? this.request.getParameterValues(aName) : null);
  +        if (getLogger().isDebugEnabled())
  +            getLogger().debug("startNonCheckableElement "+name+" attributes "+this.printAttributes(attributes));
           if (this.values != null) {
  +            if (getLogger().isDebugEnabled())
  +                getLogger().debug("replacing");
               if (value != null) {
  -                attributes.setValue(attributes.getIndex("value"), this.values[0]);
  +                attributes.setValue(attributes.getIndex("value"), String.valueOf(this.values[0]));
               } else {
  -                attributes.addAttribute("", "value","value","CDATA",this.values[0]);
  +                attributes.addAttribute("", "value","value","CDATA",String.valueOf(this.values[0]));
               }
           }
           super.startElement(uri, name, raw, (Attributes)attributes);
  -        this.values = null;
       }
   
       /**
  @@ -365,11 +446,18 @@
           String aName = attr.getValue("name");
           String fixed = attr.getValue("fixed");
   
  -        this.values = request.getParameterValues(aName);
  -        if (aName == null || this.values == null || (fixed != null && parseBoolean(fixed))) {
  +        if (getLogger().isDebugEnabled())
  +            getLogger().debug("startInputElement "+name+" attributes "+this.printAttributes(attr));
  +        if (aName == null || this.fixed || (fixed != null && parseBoolean(fixed))) {
               super.startElement(uri, name, raw, attr);
   
           } else {
  +            if (getLogger().isDebugEnabled())
  +                getLogger().debug("replacing");
  +            
  +            if (this.prefix != null) aName = this.prefix + aName;
  +            if (this.postfix != null) aName = aName + this.postfix;
  +            this.values = this.getValues(aName);
           
               AttributesImpl attributes = null;
               if (attr instanceof AttributesImpl) {
  @@ -381,11 +469,11 @@
               switch (((Integer)inputTypes.get(type,defaultType)).intValue()) {
               case TYPE_CHECKBOX:
               case TYPE_RADIO:
  -                this.startCheckableElement(uri, name, raw, attributes, aName);
  +                this.startCheckableElement(uri, name, raw, attributes);
                   break;
                   
               case TYPE_DEFAULT:
  -                this.startNonCheckableElement(uri, name, raw, attributes, aName);
  +                this.startNonCheckableElement(uri, name, raw, attributes);
                   break;
               }
               this.values=null;
  @@ -400,13 +488,17 @@
       protected void startSelectElement(String uri, String name, String raw, Attributes attr)
           throws SAXException {
   
  -        // this.selectName = @name
           // this.values = request.getParameterValues(@name)
           String aName = attr.getValue("name");
           String fixed = attr.getValue("fixed");
  -        this.selectName = attr.getValue("name");
  -        if (aName != null && (this.selectName != null || (fixed != null && parseBoolean(fixed))))
  -            this.values = this.request.getParameterValues(this.selectName);
  +        this.values = null;
  +        if (getLogger().isDebugEnabled())
  +            getLogger().debug("startSelectElement "+name+" attributes "+this.printAttributes(attr));
  +        if (aName != null && !(this.fixed || (fixed != null && parseBoolean(fixed)))) {
  +            if (this.prefix != null) aName = this.prefix + aName;
  +            if (this.postfix != null) aName = aName + this.postfix;
  +            this.values = this.getValues(aName);
  +        }
           super.startElement(uri, name, raw, attr);
       }
   
  @@ -421,9 +513,13 @@
           throws SAXException {
   
           // add @selected if @value in request.getParameterValues(@name)
  -        if (this.values == null) {
  +        if (getLogger().isDebugEnabled())
  +            getLogger().debug("startOptionElement "+name+" attributes "+this.printAttributes(attr));
  +        if (this.values == null || this.fixed) {
               super.startElement(uri, name, raw, attr);
           } else {
  +            if (getLogger().isDebugEnabled())
  +                getLogger().debug("replacing");
               AttributesImpl attributes = null;
               if (attr instanceof AttributesImpl) {
                   attributes = (AttributesImpl) attr;
  @@ -435,7 +531,7 @@
               boolean found = false;
               
               for (int i=0; i<this.values.length; i++) {
  -                if (this.values[i].equals(String.valueOf(value))) {
  +                if (this.values[i].equals(value)) {
                       found = true;
                       if (selected == null) {
                           attributes.addAttribute("","selected","selected","CDATA","");
  @@ -460,16 +556,24 @@
   
           String aName = attributes.getValue("name");
           String fixed = attributes.getValue("fixed");
  -        String[] value = null;
  -        if (aName != null) 
  -            value = this.request.getParameterValues(aName);
  -        if (value!=null || (fixed != null && (parseBoolean(fixed)))) {
  -            this.ignoreCount++;
  -            this.stack.push(name);
  +        Object[] value = null;
  +        if (getLogger().isDebugEnabled())
  +            getLogger().debug("startTextareaElement "+name+" attributes "+this.printAttributes(attributes));
  +        if (aName != null) {
  +            if (this.prefix != null) aName = this.prefix + aName;
  +            if (this.postfix != null) aName = aName + this.postfix;
  +            value = this.getValues(aName);
  +        }
  +        if (value == null || this.fixed || (fixed != null && parseBoolean(fixed))) {
               super.startElement(uri, name, raw, attributes);
  -            super.characters(value[0].toCharArray(), 0, value[0].length());
           } else {
  +            if (getLogger().isDebugEnabled())
  +                getLogger().debug("replacing");
  +            this.ignoreCount++;
  +            this.stack.push(name);
               super.startElement(uri, name, raw, attributes);
  +            String valString = String.valueOf(value[0]);
  +            super.characters(valString.toCharArray(), 0, valString.length());
           }
       }
   
  @@ -484,7 +588,9 @@
       protected void startErrorElement(String uri, String name, String raw, Attributes attr)
           throws SAXException {
           
  -        if (this.validationResults == null) {
  +        if (getLogger().isDebugEnabled())
  +            getLogger().debug("startErrorElement "+name+" attributes "+this.printAttributes(attr));
  +        if (this.validationResults == null || this.fixed) {
               this.ignoreCount++;
               this.stack.push(name);
           } else {
  @@ -492,6 +598,8 @@
               if (aName == null) {
                   super.startElement(uri, name, raw, attr);
               } else {
  +                if (this.prefix != null) aName = this.prefix + aName;
  +                if (this.postfix != null) aName = aName + this.postfix;
                   ValidatorActionResult validation = XSPFormValidatorHelper.getParamResult(this.objectModel, aName);
                   String when = attr.getValue("when");
                   String when_ge = attr.getValue("when-ge");
  @@ -593,7 +701,6 @@
                       super.endElement(uri, name, raw);
                       break;
                   case ELEMENT_SELECT:
  -                    this.selectName = null;
                       this.values = null;
                       super.endElement(uri, name, raw);
                       break;
  @@ -663,4 +770,51 @@
       private static  boolean parseBoolean(String aBoolean){
           return "true".equalsIgnoreCase(aBoolean);
       }
  +
  +    /**
  +     * Obtain values from the used InputModule.
  +     */
  +    private Object[] getValues(String name) {
  +        Object[] values = null;
  +        ComponentSelector iputSelector = null;
  +        InputModule iput = null;
  +        try {
  +            if (this.input != null) {
  +                // input module is thread safe
  +                // thus we still have a reference to it
  +                values = input.getAttributeValues(name,this.inputConf,objectModel);
  +                if (getLogger().isDebugEnabled())
  +                    getLogger().debug("cached module "+this.input+" attribute "+name+" returns "+values);
  +            } else {
  +                // input was not thread safe
  +                // so acquire it again
  +                iputSelector=(ComponentSelector) this.manager.lookup(INPUT_MODULE_SELECTOR); 
  +                if (this.inputName != null 
  +                    && iputSelector != null 
  +                    && iputSelector.hasComponent(this.inputName)) {
  +                    
  +                    iput = (InputModule) iputSelector.select(this.inputName);
  +                }
  +                if (iput != null) {
  +                    values = iput.getAttributeValues(name, this.inputConf, objectModel);
  +                }           
  +                if (getLogger().isDebugEnabled())
  +                    getLogger().debug("fresh module "+iput+" attribute "+name+" returns "+values);
  +            }
  +        } catch (Exception e) {
  +            if (getLogger().isWarnEnabled()) 
  +                getLogger().warn("A problem occurred acquiring a value from '" 
  +                                 + this.inputName + "' for '"+name+"': " + e.getMessage());
  +        } finally {
  +            // release components if necessary
  +            if (iputSelector != null) {
  +                if (iput != null)
  +                    iputSelector.release(iput);
  +                this.manager.release(iputSelector);
  +            }
  +        }
  +
  +        return values;
  +    }
  +
   }
  
  
  
  1.10      +0 -1      xml-cocoon2/src/java/org/apache/cocoon/components/modules/modules.xconf
  
  Index: modules.xconf
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/modules/modules.xconf,v
  retrieving revision 1.9
  retrieving revision 1.10
  diff -u -r1.9 -r1.10
  --- modules.xconf	13 Nov 2002 22:46:15 -0000	1.9
  +++ modules.xconf	17 Nov 2002 18:00:02 -0000	1.10
  @@ -20,7 +20,6 @@
         <component-instance logger="core.modules.input" name="xmlmeta"    	class="org.apache.cocoon.components.modules.input.XMLMetaModule"/>
         <component-instance logger="core.modules.input" name="mapmeta"    	class="org.apache.cocoon.components.modules.input.MapMetaModule"/>
         <component-instance logger="core.modules.input" name="defaults"   	class="org.apache.cocoon.components.modules.input.DefaultsMetaModule">
  -		 <input-module name="request-param"/>
   		 <values>
   			<skin>defaultSkin</skin>
   			<base-url>http://localhost:8080/cocoon</base-url>
  
  
  
  1.3       +144 -6    xml-cocoon2/src/java/org/apache/cocoon/components/modules/input/AbstractJXPathModule.java
  
  Index: AbstractJXPathModule.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/modules/input/AbstractJXPathModule.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- AbstractJXPathModule.java	28 Oct 2002 14:43:40 -0000	1.2
  +++ AbstractJXPathModule.java	17 Nov 2002 18:00:03 -0000	1.3
  @@ -57,6 +57,7 @@
   import java.util.Map;
   import java.util.Iterator;
   
  +import org.apache.avalon.framework.configuration.Configurable;
   import org.apache.avalon.framework.configuration.Configuration;
   import org.apache.avalon.framework.configuration.ConfigurationException;
   import org.apache.avalon.framework.thread.ThreadSafe;
  @@ -70,15 +71,150 @@
   import org.apache.commons.jxpath.servlet.*;
   
   /**
  - * JXPathModule allows to access properties of any object in generic way.
  - * JXPath provides APIs for the traversal of graphs of JavaBeans, DOM and other
  - * types of objects using the XPath syntax.
  + * JXPathModule allows to access properties of any object in generic
  + * way.  JXPath provides APIs for the traversal of graphs of
  + * JavaBeans, DOM and other types of objects using the XPath
  + * syntax. JXPathMetaModule is based on this class and duplicates
  + * the code since multiple inheritance is not possible. Please keep both
  + * classes in sync.
  + *
  + * <p>Configuration example:</p>
  + * <table>
  + * <tr><td><code>&lt;function name="java.lang.String" prefix="str"/&gt;</td>
  + * <td>Imports the class "String" as extension class to the JXPathContext using 
  + * the prefix "str". Thus "str:length(xpath)" would apply the method "length" to 
  + * the string object obtained from the xpath expression. Please note that the class
  + * needs to be fully qualified.</td> 
  + *</tr>
  + * <tr><td><code>&lt;package name="java.util" prefix="util"/&gt;</td>
  + * <td>Imports all classes in the package "java.util" as extension classes to the 
  + * JXPathContext using the prefix "util". Thus "util:Date.new()" would create a 
  + * new java.util.Date object.</td> 
  + * </tr></table>
    *
    * @author <a href="mailto:kpiroumian@apache.org">Konstantin Piroumian</a>
  + * @author <a href="mailto:haul@apache.org">Christian Haul</a>
    * @version $Id$
    */
  -public abstract class AbstractJXPathModule extends AbstractInputModule
  -    implements ThreadSafe {
  +public abstract class AbstractJXPathModule extends AbstractInputModule {
  +
  +    /**
  +     * Contains all globally registered extension classes and
  +     * packages. Thus the lookup and loading of globally registered
  +     * extensions is done only once.
  +     *
  +     */
  +    protected FunctionLibrary library = null;
  +
  +
  +    /**
  +     * Configure component. Preprocess list of packages and functions
  +     * to add to JXPath context later.
  +     *
  +     * @param conf a <code>Configuration</code> value
  +     * @exception ConfigurationException if an error occurs
  +     */
  +    public void configure(Configuration config) throws ConfigurationException {
  +
  +        // JXPathMetaModule starts copying here
  +        // please keep both in sync.
  +
  +        this.library = new FunctionLibrary();
  +        getFunctions(this.library, config);
  +        getPackages(this.library, config);
  +    }
  +
  +
  +
  +    /**
  +     * Register all extension functions listed in the configuration
  +     * through <code>&lt;function name="fully.qualified.Class"
  +     * prefix="prefix"/&gt;</code> in the given FunctionLibrary.
  +     *
  +     * @param lib a <code>FunctionLibrary</code> value
  +     * @param conf a <code>Configuration</code> value
  +     */
  +    protected void getFunctions(FunctionLibrary lib, Configuration conf) {
  +
  +        Configuration[] children = conf.getChildren("function");
  +        int i = children.length;
  +        while (i-- >0) {
  +            String clazzName = children[i].getAttribute("name",null);
  +            String prefix = children[i].getAttribute("prefix",null);
  +            if (clazzName != null && prefix != null) {
  +                try {
  +                    Class clazz = Class.forName(clazzName);
  +                    if (getLogger().isDebugEnabled())
  +                        getLogger().debug("adding Class "+clazzName+" to functions");
  +                    lib.addFunctions(new ClassFunctions(clazz, prefix));
  +                } catch (ClassNotFoundException cnf) {
  +                    if (getLogger().isWarnEnabled())
  +                        getLogger().warn("Class not found: "+clazzName);
  +                }
  +            } else {
  +                if (getLogger().isWarnEnabled())
  +                    getLogger().warn("Class name or prefix null: "+clazzName+" / "+prefix);
  +            }
  +        }
  +    }
  +
  +
  +    /**
  +     * Register all extension packages listed in the configuration
  +     * through <code>&lt;package name="fully.qualified.package"
  +     * prefix="prefix"/&gt;</code> in the given FunctionLibrary.
  +     *
  +     * @param lib a <code>FunctionLibrary</code> value
  +     * @param conf a <code>Configuration</code> value
  +     */
  +    protected void getPackages(FunctionLibrary lib, Configuration conf)  {
  +
  +        Configuration[] children = conf.getChildren("package");
  +        int i = children.length;
  +        while (i-- >0) {
  +            String packageName = children[i].getAttribute("name",null);
  +            String prefix = children[i].getAttribute("prefix",null);
  +            if (packageName != null && prefix != null) {
  +                if (getLogger().isDebugEnabled())
  +                    getLogger().debug("adding Package "+packageName+" to functions");
  +                lib.addFunctions(new PackageFunctions(packageName, prefix));
  +            } else {
  +                if (getLogger().isWarnEnabled())
  +                    getLogger().warn("Package name or prefix null: "+packageName+" / "+prefix);
  +            }
  +        }
  +    }
  +
  +
  +    /**
  +     * Actually add global functions and packages as well as those
  +     * listed in the configuration object.
  +     *
  +     * @param context a <code>JXPathContext</code> value
  +     * @param conf a <code>Configuration</code> value holding local
  +     * packages and functions.
  +     * @exception ConfigurationException if an error occurs
  +     */
  +    protected void setupExtensions(JXPathContext context, Configuration conf) {
  +        
  +        FunctionLibrary localLib = null;
  +
  +        if (conf != null) {
  +            if (getLogger().isDebugEnabled())
  +                getLogger().debug("adding local Classes and Packages to functions");
  +            localLib = new FunctionLibrary();
  +            localLib.addFunctions(this.library);
  +            getPackages(localLib, conf);
  +            getFunctions(localLib, conf);
  +        } else {
  +            if (getLogger().isDebugEnabled())
  +                getLogger().debug("no local Classes or Packages");
  +            localLib = this.library;
  +        }
  +        
  +        context.setFunctions(localLib);
  +    }
  +
   
       public Object getAttribute(String name, Configuration modeConf,
                                  Map objectModel)
  @@ -87,6 +223,7 @@
           try {
               Object contextObj = getContextObject(modeConf, objectModel);
               JXPathContext jxContext = JXPathContext.newContext(contextObj);
  +            setupExtensions(jxContext, modeConf);
               return jxContext.getValue(name);
           } catch (Exception e) {
               throw new ConfigurationException(
  @@ -126,6 +263,7 @@
               Object contextObj = getContextObject(modeConf, objectModel);
               JXPathContext jxContext = JXPathContext.newContext(contextObj);
               List values = new LinkedList();
  +            setupExtensions(jxContext, modeConf);
               Iterator i = jxContext.iterate(name);
               while (i.hasNext()) {
                   values.add(i.next());
  
  
  
  1.3       +19 -16    xml-cocoon2/src/java/org/apache/cocoon/components/modules/input/AbstractMetaModule.java
  
  Index: AbstractMetaModule.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/modules/input/AbstractMetaModule.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- AbstractMetaModule.java	28 Oct 2002 14:43:40 -0000	1.2
  +++ AbstractMetaModule.java	17 Nov 2002 18:00:03 -0000	1.3
  @@ -75,7 +75,7 @@
    * @version CVS $Id$
    */
   public abstract class AbstractMetaModule extends AbstractInputModule
  -    implements InputModule, Configurable, Initializable, Composable, Disposable {
  +    implements Initializable, Composable, Disposable {
   
       /** The component manager instance */
       protected ComponentManager manager;
  @@ -94,7 +94,7 @@
                                                  // during configure() so why bother here...
       
       /** Is this instance initialized? */
  -    protected boolean initialized = false;
  +    protected Boolean initialized = new Boolean(false);
   
       /* Constants */
   
  @@ -125,19 +125,22 @@
   
           try {
               // obtain input modules
  -            this.inputSelector=(ComponentSelector) this.manager.lookup(INPUT_MODULE_SELECTOR); 
  -            if (this.inputSelector != null && this.inputSelector instanceof ThreadSafe) {
  -                
  -                if (this.defaultInput != null) 
  -                    this.input = obtainModule(this.defaultInput);
  -
  -            } else if (!(this.inputSelector instanceof ThreadSafe) ) {
  -                this.manager.release(this.inputSelector);
  -                this.inputSelector = null;
  +            synchronized (this.initialized) {
  +                if (!this.initialized.booleanValue()) 
  +                    this.inputSelector=(ComponentSelector) this.manager.lookup(INPUT_MODULE_SELECTOR); 
  +                    if (this.inputSelector != null && this.inputSelector instanceof ThreadSafe) {
  +                        
  +                        if (this.defaultInput != null) {
  +                            this.input = obtainModule(this.defaultInput);
  +                        }
  +                        
  +                    } else if (!(this.inputSelector instanceof ThreadSafe) ) {
  +                        this.manager.release(this.inputSelector);
  +                        this.inputSelector = null;
  +                    }
  +                    
  +                    this.initialized = new Boolean(true);
               }
  -
  -            this.initialized = true;
  -
           } catch (Exception e) {
               if (getLogger().isWarnEnabled()) 
                   getLogger().warn("A problem occurred setting up input modules :'" + e.getMessage());
  @@ -151,7 +154,7 @@
        */
       public void dispose() {
   
  -        if (!this.initialized) 
  +        if (!this.initialized.booleanValue()) 
               if (getLogger().isErrorEnabled()) 
                   getLogger().error("Uninitialized Component! FAILING");
           else 
  
  
  
  1.3       +24 -25    xml-cocoon2/src/java/org/apache/cocoon/components/modules/input/ChainMetaModule.java
  
  Index: ChainMetaModule.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/modules/input/ChainMetaModule.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- ChainMetaModule.java	28 Oct 2002 14:43:40 -0000	1.2
  +++ ChainMetaModule.java	17 Nov 2002 18:00:03 -0000	1.3
  @@ -96,7 +96,7 @@
    * @author <a href="mailto:haul@informatik.tu-darmstadt.de">Christian Haul</a>
    * @version CVS $Id$
    */
  -public class ChainMetaModule extends AbstractMetaModule {
  +public class ChainMetaModule extends AbstractMetaModule  {
   
       class ModuleHolder {
           public String name = null;
  @@ -110,9 +110,6 @@
       private boolean allNames = false;
       private boolean allValues = false;
   
  -    private boolean initialized = false;
  -
  -
       public void configure(Configuration config) throws ConfigurationException {
   
           Configuration[] confs = config.getChildren("input-module");
  @@ -142,21 +139,23 @@
   
           try {
               // obtain input modules
  -            this.inputSelector=(ComponentSelector) this.manager.lookup(INPUT_MODULE_SELECTOR); 
  -            if (this.inputSelector != null && this.inputSelector instanceof ThreadSafe) {
  -
  -                for (int i=0; i<this.inputs.length; i++) {
  -                    if (this.inputs[i].name != null) 
  -                        this.inputs[i].input = obtainModule(this.inputs[i].name);
  -                }
  -
  -            } else if (!(this.inputSelector instanceof ThreadSafe) ) {
  -                this.manager.release(this.inputSelector);
  -                this.inputSelector = null;
  +            synchronized (this.initialized) {
  +                if (!this.initialized.booleanValue())
  +                    this.inputSelector=(ComponentSelector) this.manager.lookup(INPUT_MODULE_SELECTOR); 
  +                    if (this.inputSelector != null && this.inputSelector instanceof ThreadSafe) {
  +                        
  +                        for (int i=0; i<this.inputs.length; i++) {
  +                            if (this.inputs[i].name != null) 
  +                                this.inputs[i].input = obtainModule(this.inputs[i].name);
  +                        }
  +                        
  +                    } else if (!(this.inputSelector instanceof ThreadSafe) ) {
  +                        this.manager.release(this.inputSelector);
  +                        this.inputSelector = null;
  +                    }
  +                    
  +                    this.initialized = new Boolean(true);
               }
  -
  -            this.initialized = true;
  -
           } catch (Exception e) {
               if (getLogger().isWarnEnabled()) 
                   getLogger().warn("A problem occurred setting up input modules :'" + e.getMessage());
  @@ -166,9 +165,9 @@
       
       public void dispose() {
           
  -        if (!this.initialized) 
  +        if (!this.initialized.booleanValue()) 
               if (getLogger().isErrorEnabled()) 
  -                getLogger().error("Uninitialized Component! FAILING");
  +                getLogger().error("Uninitialized Component! dispose() FAILING");
               else 
                   if (this.inputSelector != null) {
                       
  @@ -185,9 +184,9 @@
       public Object[] getAttributeValues( String attr, Configuration modeConf, Map objectModel ) 
           throws ConfigurationException {
   
  -        if (!this.initialized) {
  +        if (!this.initialized.booleanValue()) {
               if (getLogger().isErrorEnabled()) 
  -                getLogger().error("Uninitialized Component! FAILING");
  +                getLogger().error("Uninitialized Component! getAttributeValues() FAILING");
               return null;
           }
   
  @@ -250,9 +249,9 @@
           throws ConfigurationException {
   
   
  -        if (!this.initialized) {
  +        if (!this.initialized.booleanValue()) {
               if (getLogger().isErrorEnabled()) 
  -                getLogger().error("Uninitialized Component! FAILING");
  +                getLogger().error("Uninitialized Component! getAttributeNames() FAILING");
               return null;
           }
   
  
  
  
  1.3       +11 -10    xml-cocoon2/src/java/org/apache/cocoon/components/modules/input/DateMetaInputModule.java
  
  Index: DateMetaInputModule.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/modules/input/DateMetaInputModule.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- DateMetaInputModule.java	28 Oct 2002 14:43:40 -0000	1.2
  +++ DateMetaInputModule.java	17 Nov 2002 18:00:03 -0000	1.3
  @@ -53,6 +53,7 @@
   
   import org.apache.avalon.framework.configuration.Configuration;
   import org.apache.avalon.framework.configuration.ConfigurationException;
  +import org.apache.avalon.framework.thread.ThreadSafe;
   
   import java.util.Map;
   import java.util.Iterator;
  @@ -61,7 +62,11 @@
   import java.text.SimpleDateFormat;
   
   /**
  - * Parses a date string according to a given format and returns a date object.
  + * Parses a date string according to a given format and returns a date
  + * object. Configuration options: child element "input-module" holds
  + * InputModule to obtain the string from, attribute "format" to
  + * "input-module" that holds ajava.text.SimpleDateFormat format
  + * string.
    *
    * @author <a href="mailto:haul@informatik.tu-darmstadt.de">Christian Haul</a>
    * @version CVS $Id$
  @@ -86,7 +91,7 @@
       public Object[] getAttributeValues( String name, Configuration modeConf, Map objectModel ) 
           throws ConfigurationException {
   
  -        if (!this.initialized) {
  +        if (!this.initialized.booleanValue()) {
               if (getLogger().isErrorEnabled()) 
                   getLogger().error("Uninitialized Component! FAILING");
               return null;
  @@ -98,20 +103,16 @@
   
           // obtain correct configuration objects
           // default vs dynamic
  -        Configuration inputConfig = this.inputConf;
           Configuration mConf = null;
           String inputName=null;
           String parameter=name;
           String format=null;
           DateFormat formatter=null;
           if (modeConf!=null) {
  -            mConf       = modeConf.getChild("values");
  +            mConf       = modeConf.getChild("input-module");
               inputName   = modeConf.getChild("input-module").getAttribute("name",null);
               parameter   = modeConf.getAttribute("parameter",parameter);
               format      = modeConf.getAttribute("format",this.defaultFormat);
  -            if (inputName != null) {
  -                inputConfig = modeConf.getChild("input-module");
  -            }
           }
           if (this.defaultFormat.equals(format)) {
               formatter = this.defaultFormatter;
  @@ -145,7 +146,7 @@
       public Iterator getAttributeNames( Configuration modeConf, Map objectModel ) 
           throws ConfigurationException {
   
  -        if (!this.initialized) {
  +        if (!this.initialized.booleanValue()) {
               if (getLogger().isErrorEnabled()) 
                   getLogger().error("Uninitialized Component! FAILING");
               return null;
  @@ -161,7 +162,7 @@
           Configuration mConf = null;
           String inputName=null;
           if (modeConf!=null) {
  -            mConf       = modeConf.getChild("values");
  +            mConf       = modeConf.getChild("input-module");
               inputName   = modeConf.getChild("input-module").getAttribute("name",null);
               if (inputName != null) {
                   inputConfig = modeConf.getChild("input-module");
  
  
  
  1.6       +11 -192   xml-cocoon2/src/java/org/apache/cocoon/components/modules/input/DefaultsMetaModule.java
  
  Index: DefaultsMetaModule.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/modules/input/DefaultsMetaModule.java,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- DefaultsMetaModule.java	28 Oct 2002 14:43:40 -0000	1.5
  +++ DefaultsMetaModule.java	17 Nov 2002 18:00:03 -0000	1.6
  @@ -51,15 +51,9 @@
   package org.apache.cocoon.components.modules.input;
   
   
  -import org.apache.avalon.framework.activity.Disposable;
  -import org.apache.avalon.framework.activity.Initializable;
   import org.apache.avalon.framework.configuration.Configurable;
   import org.apache.avalon.framework.configuration.Configuration;
   import org.apache.avalon.framework.configuration.ConfigurationException;
  -import org.apache.avalon.framework.component.ComponentSelector;
  -import org.apache.avalon.framework.component.ComponentException;
  -import org.apache.avalon.framework.component.ComponentManager;
  -import org.apache.avalon.framework.component.Composable;
   import org.apache.avalon.framework.logger.AbstractLogEnabled;
   import org.apache.avalon.framework.parameters.Parameters;
   import org.apache.avalon.framework.thread.ThreadSafe;
  @@ -74,10 +68,11 @@
   import java.util.TreeSet;
   
   /**
  - * Set a number of constants that may be overridden by output from
  - * another input module.
  + * Set a number of constants. To override the values with input from
  + * another module, combine this one with the ChainMetaModule and an
  + * arbitrary number of other modules. IOW this is no "meta" module
  + * anymore!
    *
  - * &lt;input-module&gt;some-other-module&lt;/input-module&gt;
    * &lt;values&gt;
    *  &lt;skin&gt;myskin&lt;/skin&gt;
    *  &lt;base&gt;baseurl&lt;/base&gt;
  @@ -87,38 +82,12 @@
    * @version CVS $Id$
    */
   public class DefaultsMetaModule extends AbstractLogEnabled
  -    implements InputModule, Configurable, Initializable, Composable, Disposable {
  +    implements InputModule, Configurable, ThreadSafe {
   
  -    /** The component manager instance */
  -    protected ComponentManager manager;
  -
  -    private String defaultInput = null;
  -    private Configuration inputConf = null;  // will become an empty configuration object
  -                                             // during configure() so why bother here...
  -    String INPUT_MODULE_ROLE = InputModule.ROLE;
  -    String INPUT_MODULE_SELECTOR = INPUT_MODULE_ROLE+"Selector";
  -
  -    private boolean initialized = false;
  -    private InputModule input = null;
  -    private ComponentSelector inputSelector = null;
       private Map constants = null;
  -
  -
  -    /**
  -     * Set the current <code>ComponentManager</code> instance used by this
  -     * <code>Composable</code>.
  -     */
  -    public void compose(ComponentManager manager) throws ComponentException {
  -
  -        this.manager=manager;
  -    }
  -
  -
       
       public void configure(Configuration config) throws ConfigurationException {
   
  -        this.inputConf = config.getChild("input-module");
  -        this.defaultInput = this.inputConf.getAttribute("name",this.defaultInput);
           this.constants = new HashMap();
           Configuration[] consts = config.getChild("values").getChildren();
           for (int i=0; i<consts.length; i++) {
  @@ -127,173 +96,25 @@
       }
   
   
  -
  -    public void initialize() {
  -
  -        try {
  -            // obtain input module
  -            this.inputSelector=(ComponentSelector) this.manager.lookup(INPUT_MODULE_SELECTOR); 
  -            if (this.defaultInput != null && 
  -                this.inputSelector != null && 
  -                this.inputSelector.hasComponent(this.defaultInput)
  -                ){
  -                this.input = (InputModule) this.inputSelector.select(this.defaultInput);
  -                if (!(this.input instanceof ThreadSafe && this.inputSelector instanceof ThreadSafe) ) {
  -                    this.inputSelector.release(this.input);
  -                    this.manager.release(this.inputSelector);
  -                    this.input = null;
  -                    this.inputSelector = null;
  -                }
  -                this.initialized = true;
  -            } else {
  -                if (this.defaultInput != null)
  -                    if (getLogger().isErrorEnabled())
  -                        getLogger().error("A problem occurred setting up '" + this.defaultInput 
  -                                          +"': Selector is "+(this.inputSelector!=null?"not ":"")
  -                                          +"null, Component is "
  -                                          +(this.inputSelector!=null&&this.inputSelector.hasComponent(this.defaultInput)?"known":"unknown"));
  -                this.initialized = true;
  -            }
  -        } catch (Exception e) {
  -            if (getLogger().isWarnEnabled()) 
  -                getLogger().warn("A problem occurred setting up '" + this.defaultInput + "': " + e.getMessage());
  -        }
  -    }
  -
  -
  -
  -    public void dispose() {
  -
  -        if (!this.initialized) 
  -            if (getLogger().isErrorEnabled()) 
  -                getLogger().error("Uninitialized Component! FAILING");
  -        else 
  -            if (this.inputSelector != null) {
  -                if (this.input != null)
  -                    this.inputSelector.release(this.input);
  -                this.manager.release(this.inputSelector);
  -            }
  -    }
  -
  -
  -    
  -
       public Object[] getAttributeValues( String name, Configuration modeConf, Map objectModel ) 
           throws ConfigurationException {
   
  -        if (!this.initialized) {
  -            if (getLogger().isErrorEnabled()) 
  -                getLogger().error("Uninitialized Component! FAILING");
  -            return null;
  -        }
  -        if (this.defaultInput == null) {
  -            if (getLogger().isWarnEnabled()) 
  -                getLogger().warn("No input module given");
  -        }
  -
  -        // obtain correct configuration objects
  -        // default vs dynamic
  -        Configuration inputConfig = this.inputConf;
  -        Configuration mConf = null;
  -        String inputName=null;
           String parameter=name;
  +        Configuration mConf = null;
           if (modeConf!=null) {
               mConf       = modeConf.getChild("values");
  -            inputName   = modeConf.getChild("input-module").getAttribute("name",null);
  -            parameter   = modeConf.getAttribute("parameter",parameter);
  -            if (inputName != null) {
  -                inputConfig = modeConf.getChild("input-module");
  -            }
           }
   
  -        // done reading configuration
  -        // setup modules and read values
  -        Object[] values = null;
  -        try {
  -            if (this.defaultInput != null || inputName != null) {
  -                if (this.input != null && inputName == null) {
  -                    // input module is thread safe
  -                    // thus we still have a reference to it
  -                    // and
  -                    // no other module is configured dynamically
  -                    values = input.getAttributeValues(parameter,this.inputConf,objectModel);
  -                } else {
  -                    // input was not thread safe
  -                    // or
  -                    // another module is configured dynamically
  -                    // so acquire it again
  -                    ComponentSelector iputSelector = null;
  -                    InputModule iput = null;
  -                    try {
  -                        // obtain input module
  -                        if (inputName == null) {
  -                            inputName   = this.defaultInput;
  -                            inputConfig = this.inputConf;
  -                        }
  -                        
  -                        iputSelector=(ComponentSelector) this.manager.lookup(INPUT_MODULE_SELECTOR); 
  -                        if (inputName != null 
  -                            && iputSelector != null 
  -                            && iputSelector.hasComponent(inputName)) {
  -                            
  -                            iput = (InputModule) iputSelector.select(inputName);
  -                        }
  -                        if (iput != null) {
  -                            values = iput.getAttributeValues(parameter, inputConfig, objectModel);
  -                        }           
  -                    } catch (Exception e) {
  -                        if (getLogger().isWarnEnabled()) 
  -                            getLogger().warn("A problem occurred acquiring a value from '" 
  -                                             + inputName + "' for '"+name+"': " + e.getMessage());
  -                    } finally {
  -                        // release components
  -                        if (iputSelector != null) {
  -                            if (iput != null)
  -                                iputSelector.release(iput);
  -                            this.manager.release(iputSelector);
  -                        }
  -                    }
  -                    
  -                }
  -            }
  -            
  -            // done reading values
  -            // start converting values and assemble array
  -
  -            if (values == null) {
  -                values = new Object[1];
  -                values[0] = (mConf!=null?mConf.getChild(parameter).getValue((String) this.constants.get(parameter)) : this.constants.get(parameter));
  -            }
  -            return values;
  -        } catch (Exception e) {
  -            if (getLogger().isWarnEnabled()) 
  -                getLogger().warn("A problem occurred acquiring a value from '" + inputName 
  -                                 + "' for '"+name+"': " + e.getMessage());
  -        }
  -        return null;        
  +        Object[] values = new Object[1];
  +        values[0] = (mConf!=null? mConf.getChild(parameter).getValue((String) this.constants.get(parameter)) 
  +                     : this.constants.get(parameter));
  +        return values;
       }
   
   
  -
  -
  -
       public Iterator getAttributeNames( Configuration modeConf, Map objectModel ) 
           throws ConfigurationException {
   
  -        if (!this.initialized) {
  -            if (getLogger().isErrorEnabled()) 
  -                getLogger().error("Uninitialized Component! FAILING");
  -            return null;
  -        }
  -        if (this.defaultInput == null) {
  -            if (getLogger().isWarnEnabled()) 
  -                getLogger().warn("No input module given. FAILING");
  -            return null;
  -        }
  -
  -        // obtain correct configuration objects
  -        // default vs dynamic
  -
           SortedSet matchset = new TreeSet(this.constants.keySet());
           if (modeConf!=null) {
               Configuration[] consts = modeConf.getChild("values").getChildren();
  @@ -302,8 +123,6 @@
           }
           return matchset.iterator();
        }
  -
  -
   
   
       public Object getAttribute( String name, Configuration modeConf, Map objectModel ) 
  
  
  
  1.7       +5 -4      xml-cocoon2/src/java/org/apache/cocoon/components/modules/input/DigestMetaModule.java
  
  Index: DigestMetaModule.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/modules/input/DigestMetaModule.java,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- DigestMetaModule.java	28 Oct 2002 14:43:40 -0000	1.6
  +++ DigestMetaModule.java	17 Nov 2002 18:00:03 -0000	1.7
  @@ -52,6 +52,7 @@
   
   import org.apache.avalon.framework.configuration.Configuration;
   import org.apache.avalon.framework.configuration.ConfigurationException;
  +import org.apache.avalon.framework.thread.ThreadSafe;
   
   import java.net.URLEncoder;
   
  @@ -94,7 +95,7 @@
       public Object getAttribute( String name, Configuration modeConf, Map objectModel ) 
           throws ConfigurationException {
   
  -        if (!this.initialized) {
  +        if (!this.initialized.booleanValue()) {
               if (getLogger().isErrorEnabled()) 
                   getLogger().error("Uninitialized Component! FAILING");
               return null;
  @@ -159,7 +160,7 @@
       public Iterator getAttributeNames( Configuration modeConf, Map objectModel ) 
           throws ConfigurationException {
   
  -         if (!this.initialized) {
  +         if (!this.initialized.booleanValue()) {
               if (getLogger().isErrorEnabled()) 
                   getLogger().error("Uninitialized Component! FAILING");
               return null;
  @@ -195,7 +196,7 @@
       public Object[] getAttributeValues( String name, Configuration modeConf, Map objectModel ) 
           throws ConfigurationException {
   
  -        if (!this.initialized) {
  +        if (!this.initialized.booleanValue()) {
               if (getLogger().isErrorEnabled()) 
                   getLogger().error("Uninitialized Component! FAILING");
               return null;
  
  
  
  1.5       +4 -5      xml-cocoon2/src/java/org/apache/cocoon/components/modules/input/MapMetaModule.java
  
  Index: MapMetaModule.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/modules/input/MapMetaModule.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- MapMetaModule.java	28 Oct 2002 14:43:40 -0000	1.4
  +++ MapMetaModule.java	17 Nov 2002 18:00:03 -0000	1.5
  @@ -52,6 +52,7 @@
   
   import org.apache.avalon.framework.configuration.Configuration;
   import org.apache.avalon.framework.configuration.ConfigurationException;
  +import org.apache.avalon.framework.thread.ThreadSafe;
   
   import java.util.Map;
   import java.util.Iterator;
  @@ -69,8 +70,6 @@
    */
   public class MapMetaModule extends AbstractMetaModule {
   
  -    private boolean initialized = false;
  -
       protected String objectName = null;
       protected String parameter = null;
   
  @@ -86,7 +85,7 @@
       public Object getAttribute( String name, Configuration modeConf, Map objectModel ) 
           throws ConfigurationException {
   
  -        if (!this.initialized) {
  +        if (!this.initialized.booleanValue()) {
               if (getLogger().isErrorEnabled()) 
                   getLogger().error("Uninitialized Component! FAILING");
               return null;
  @@ -129,7 +128,7 @@
       public Iterator getAttributeNames( Configuration modeConf, Map objectModel ) 
           throws ConfigurationException {
   
  -         if (!this.initialized) {
  +         if (!this.initialized.booleanValue()) {
               if (getLogger().isErrorEnabled()) 
                   getLogger().error("Uninitialized Component! FAILING");
               return null;
  
  
  
  1.5       +5 -4      xml-cocoon2/src/java/org/apache/cocoon/components/modules/input/XMLMetaModule.java
  
  Index: XMLMetaModule.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/modules/input/XMLMetaModule.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- XMLMetaModule.java	28 Oct 2002 14:43:40 -0000	1.4
  +++ XMLMetaModule.java	17 Nov 2002 18:00:03 -0000	1.5
  @@ -52,6 +52,7 @@
   
   import org.apache.avalon.framework.configuration.Configuration;
   import org.apache.avalon.framework.configuration.ConfigurationException;
  +import org.apache.avalon.framework.thread.ThreadSafe;
   
   import java.util.Map;
   import java.util.Iterator;
  @@ -134,7 +135,7 @@
       public Object getAttribute( String name, Configuration modeConf, Map objectModel ) 
           throws ConfigurationException {
   
  -        if (!this.initialized) {
  +        if (!this.initialized.booleanValue()) {
               if (getLogger().isErrorEnabled()) 
                   getLogger().error("Uninitialized Component! FAILING");
               return null;
  @@ -208,7 +209,7 @@
       public Iterator getAttributeNames( Configuration modeConf, Map objectModel ) 
           throws ConfigurationException {
   
  -         if (!this.initialized) {
  +         if (!this.initialized.booleanValue()) {
               if (getLogger().isErrorEnabled()) 
                   getLogger().error("Uninitialized Component! FAILING");
               return null;
  @@ -228,7 +229,7 @@
       public Object[] getAttributeValues( String name, Configuration modeConf, Map objectModel ) 
           throws ConfigurationException {
   
  -        if (!this.initialized) {
  +        if (!this.initialized.booleanValue()) {
               if (getLogger().isErrorEnabled()) 
                   getLogger().error("Uninitialized Component! FAILING");
               return null;
  
  
  
  1.1                  xml-cocoon2/src/java/org/apache/cocoon/components/modules/input/JXPathMetaModule.java
  
  Index: JXPathMetaModule.java
  ===================================================================
  /*
  
   ============================================================================
                     The Apache Software License, Version 1.1
   ============================================================================
  
   Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
  
   Redistribution and use in source and binary forms, with or without modifica-
   tion, are permitted provided that the following conditions are met:
  
   1. Redistributions of  source code must  retain the above copyright  notice,
      this list of conditions and the following disclaimer.
  
   2. Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
  
   3. The end-user documentation included with the redistribution, if any, must
      include  the following  acknowledgment:  "This product includes  software
      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
      Alternately, this  acknowledgment may  appear in the software itself,  if
      and wherever such third-party acknowledgments normally appear.
  
   4. The names "Apache Cocoon" and  "Apache Software Foundation" must  not  be
      used to  endorse or promote  products derived from  this software without
      prior written permission. For written permission, please contact
      apache@apache.org.
  
   5. Products  derived from this software may not  be called "Apache", nor may
      "Apache" appear  in their name,  without prior written permission  of the
      Apache Software Foundation.
  
   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
   FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
   APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
   INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
   DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
   OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
   ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
   (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  
   This software  consists of voluntary contributions made  by many individuals
   on  behalf of the Apache Software  Foundation and was  originally created by
   Stefano Mazzocchi  <st...@apache.org>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  
  package org.apache.cocoon.components.modules.input;
  
  import java.util.Iterator;
  import java.util.LinkedList;
  import java.util.List;
  import java.util.Map;
  import java.util.Iterator;
  
  import org.apache.avalon.framework.configuration.Configurable;
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.configuration.ConfigurationException;
  import org.apache.avalon.framework.thread.ThreadSafe;
  
  import org.apache.cocoon.environment.ObjectModelHelper;
  import org.apache.cocoon.environment.Request;
  import org.apache.cocoon.environment.Session;
  import org.apache.cocoon.environment.Context;
  
  import org.apache.commons.jxpath.*;
  import org.apache.commons.jxpath.servlet.*;
  
  /**
   * JXPathModule allows to access properties of any object in generic
   * way.  JXPath provides APIs for the traversal of graphs of
   * JavaBeans, DOM and other types of objects using the XPath
   * syntax. This is based on the AbstractJXPathModule and duplicates
   * the code since multiple inheritance is not possible. Please keep both
   * classes in sync.
   *
   * <p>Configuration example:</p>
   * <table>
   * <tr><td><code>&lt;input-module name="request-attr" parameter="foo"/&gt;</td>
   * <td>Uses the "request-attr" input module to obtain parameter named "foo" and 
   *     applies the given JXPath expression to it.</td> 
   *</tr>
   * <tr><td><code>&lt;function name="java.lang.String" prefix="str"/&gt;</td>
   * <td>Imports the class "String" as extension class to the JXPathContext using 
   * the prefix "str". Thus "str:length(xpath)" would apply the method "length" to 
   * the string object obtained from the xpath expression. Please note that the class
   * needs to be fully qualified.</td> 
   *</tr>
   * <tr><td><code>&lt;package name="java.util" prefix="util"/&gt;</td>
   * <td>Imports all classes in the package "java.util" as extension classes to the 
   * JXPathContext using the prefix "util". Thus "util:Date.new()" would create a 
   * new java.util.Date object.</td> 
   * </tr></table>
   *
   * @author <a href="mailto:kpiroumian@apache.org">Konstantin Piroumian</a>
   * @author <a href="mailto:haul@apache.org">Christian Haul</a>
   * @version $Id: JXPathMetaModule.java,v 1.1 2002/11/17 18:00:03 haul Exp $
   */
  public class JXPathMetaModule extends AbstractMetaModule implements Configurable {
  
      /**
       * Contains all globally registered extension classes and
       * packages. Thus the lookup and loading of globally registered
       * extensions is done only once.
       *
       */
      protected FunctionLibrary library = null;
      protected String parameter = null;
  
  
      public JXPathMetaModule() {
          // this value has a default in the super class
          this.defaultInput = "request-attr";
      }
  
  
      /**
       * Configure component. Preprocess list of packages and functions
       * to add to JXPath context later.
       *
       * @param conf a <code>Configuration</code> value
       * @exception ConfigurationException if an error occurs
       */
      public void configure(Configuration config) throws ConfigurationException {
  
          this.inputConf = config.getChild("input-module");
          this.defaultInput = this.inputConf.getAttribute("name",this.defaultInput);
          this.parameter = this.inputConf.getAttribute("parameter", this.parameter);
  
          // start verbatim copy of AbstractJXPathModule
          // please keep both in sync.
  
          this.library = new FunctionLibrary();
          getFunctions(this.library, config);
          getPackages(this.library, config);
      }
  
  
  
      /**
       * Register all extension functions listed in the configuration
       * through <code>&lt;function name="fully.qualified.Class"
       * prefix="prefix"/&gt;</code> in the given FunctionLibrary.
       *
       * @param lib a <code>FunctionLibrary</code> value
       * @param conf a <code>Configuration</code> value
       */
      protected void getFunctions(FunctionLibrary lib, Configuration conf) {
  
          Configuration[] children = conf.getChildren("function");
          int i = children.length;
          while (i-- >0) {
              String clazzName = children[i].getAttribute("name",null);
              String prefix = children[i].getAttribute("prefix",null);
              if (clazzName != null && prefix != null) {
                  try {
                      Class clazz = Class.forName(clazzName);
                      if (getLogger().isDebugEnabled())
                          getLogger().debug("adding Class "+clazzName+" to functions");
                      lib.addFunctions(new ClassFunctions(clazz, prefix));
                  } catch (ClassNotFoundException cnf) {
                      if (getLogger().isWarnEnabled())
                          getLogger().warn("Class not found: "+clazzName);
                  }
              } else {
                  if (getLogger().isWarnEnabled())
                      getLogger().warn("Class name or prefix null: "+clazzName+" / "+prefix);
              }
          }
      }
  
  
      /**
       * Register all extension packages listed in the configuration
       * through <code>&lt;package name="fully.qualified.package"
       * prefix="prefix"/&gt;</code> in the given FunctionLibrary.
       *
       * @param lib a <code>FunctionLibrary</code> value
       * @param conf a <code>Configuration</code> value
       */
      protected void getPackages(FunctionLibrary lib, Configuration conf)  {
  
          Configuration[] children = conf.getChildren("package");
          int i = children.length;
          while (i-- >0) {
              String packageName = children[i].getAttribute("name",null);
              String prefix = children[i].getAttribute("prefix",null);
              if (packageName != null && prefix != null) {
                  if (getLogger().isDebugEnabled())
                      getLogger().debug("adding Package "+packageName+" to functions");
                  lib.addFunctions(new PackageFunctions(packageName, prefix));
              } else {
                  if (getLogger().isWarnEnabled())
                      getLogger().warn("Package name or prefix null: "+packageName+" / "+prefix);
              }
          }
      }
  
  
      /**
       * Actually add global functions and packages as well as those
       * listed in the configuration object.
       *
       * @param context a <code>JXPathContext</code> value
       * @param conf a <code>Configuration</code> value holding local
       * packages and functions.
       * @exception ConfigurationException if an error occurs
       */
      protected void setupExtensions(JXPathContext context, Configuration conf) {
          
          FunctionLibrary localLib = null;
  
          if (conf != null) {
              if (getLogger().isDebugEnabled())
                  getLogger().debug("adding local Classes and Packages to functions");
              localLib = new FunctionLibrary();
              localLib.addFunctions(this.library);
              getPackages(localLib, conf);
              getFunctions(localLib, conf);
          } else {
              if (getLogger().isDebugEnabled())
                  getLogger().debug("no local Classes or Packages");
              localLib = this.library;
          }
          
          context.setFunctions(localLib);
      }
  
  
      public Object getAttribute(String name, Configuration modeConf,
                                 Map objectModel)
          throws ConfigurationException {
  
          try {
              Object contextObj = getContextObject(modeConf, objectModel);
              JXPathContext jxContext = JXPathContext.newContext(contextObj);
              setupExtensions(jxContext, modeConf);
              return jxContext.getValue(name);
          } catch (Exception e) {
              throw new ConfigurationException(
                  "Module does not support <" + name + ">" + "attribute.",
                  e
              );
          }
      }
  
      public Iterator getAttributeNames(Configuration modeConf, Map objectModel)
          throws ConfigurationException {
  
          Object contextObj = getContextObject(modeConf, objectModel);
          try {
              JXPathBeanInfo info = JXPathIntrospector.getBeanInfo(
                  contextObj.getClass());
              java.beans.PropertyDescriptor[] properties = info.getPropertyDescriptors();
              java.util.List names = new java.util.LinkedList();
              for (int i = 0; i < properties.length; i++) {
                  names.add(properties[i].getName());
              }
              return (java.util.Iterator) names.listIterator();
          } catch (Exception e) {
              throw new ConfigurationException(
                  "Error retrieving attribute names for class: "
                  + contextObj.getClass(),
                  e
              );
          }
  
      }
  
      public Object[] getAttributeValues(String name, Configuration modeConf, Map objectModel)
          throws ConfigurationException {
  
          try {
              Object contextObj = getContextObject(modeConf, objectModel);
              JXPathContext jxContext = JXPathContext.newContext(contextObj);
              List values = new LinkedList();
              setupExtensions(jxContext, modeConf);
              Iterator i = jxContext.iterate(name);
              while (i.hasNext()) {
                  values.add(i.next());
              }
              return values.toArray();
          } catch (Exception e) {
              throw new ConfigurationException(
                  "Module does not support <" + name + ">" + "attribute.",
                  e
              );
          }
      }
  
      // end verbatim copy of AbstractJXPathModule
  
      /**
       * Looks up object from configured InputModule. 
       *
       * @param modeConf a <code>Configuration</code> value
       * @param objectModel a <code>Map</code> value
       * @return an <code>Object</code> value
       */
      protected  Object getContextObject(Configuration modeConf, Map objectModel) {
  
          Configuration mConf = null;
          String inputName=null;
          String parameter = this.parameter;
          if (modeConf!=null) {
              inputName   = modeConf.getChild("input-module").getAttribute("name",null);
              parameter   = modeConf.getAttribute("parameter",parameter);
          }
          return this.getValue(parameter, objectModel, 
                               this.input, this.defaultInput, this.inputConf,
                               null, inputName, modeConf);
      }
  
  }
  
  
  
  1.3       +3 -3      xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/components/modules/input/CollectionMetaModule.java
  
  Index: CollectionMetaModule.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/components/modules/input/CollectionMetaModule.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- CollectionMetaModule.java	28 Oct 2002 14:43:41 -0000	1.2
  +++ CollectionMetaModule.java	17 Nov 2002 18:00:03 -0000	1.3
  @@ -100,7 +100,7 @@
       public Object getAttribute( String name, Configuration modeConf, Map objectModel ) 
           throws ConfigurationException {
   
  -        if (!this.initialized) {
  +        if (!this.initialized.booleanValue()) {
               if (getLogger().isErrorEnabled()) 
                   getLogger().error("Uninitialized Component! FAILING");
               return null;
  @@ -165,7 +165,7 @@
       public Iterator getAttributeNames( Configuration modeConf, Map objectModel ) 
           throws ConfigurationException {
   
  -        if (!this.initialized) {
  +        if (!this.initialized.booleanValue()) {
               if (getLogger().isErrorEnabled()) 
                   getLogger().error("Uninitialized Component! FAILING");
               return null;
  
  
  
  1.3       +47 -24    xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/components/language/markup/xsp/EsqlHelper.java
  
  Index: EsqlHelper.java
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/components/language/markup/xsp/EsqlHelper.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- EsqlHelper.java	6 Nov 2002 18:18:30 -0000	1.2
  +++ EsqlHelper.java	17 Nov 2002 18:00:04 -0000	1.3
  @@ -115,10 +115,11 @@
   
       /** returns byte array from BLOB
        */
  -    public final static byte[] getBlob(CallableStatement cs, int column) throws java.lang.Exception {
  +    public final static byte[] getBlob(CallableStatement cs, int column, String defaultString) throws java.lang.Exception {
           
           InputStream reader = null;
           byte[] buffer = null;
  +	byte[] result = null;
       
           try {
               Blob dbBlob = cs.getBlob(column);
  @@ -129,21 +130,23 @@
               reader.close();
               if (reader != null)
                   reader.close();
  -            if (buffer == null)
  -                return null;
  -            return buffer;
  +	    if(buffer != null) result = buffer;
  +	    else if(defaultString != null && !defaultString.equals("_null_"))
  +		result = defaultString.getBytes();
  +	    else result = null;
           } catch ( Exception e) {
               throw new RuntimeException("Error getting blob data: " + e.getMessage());
           }
  +	return result;
       }
   
       /** returns Unicode encoded string from CLOB or String column 
        */
  -    public final static String getStringOrClob(ResultSet set, String column) throws RuntimeException {
  +    public final static String getStringOrClob(ResultSet set, String column, String defaultString) throws RuntimeException {
           
           String result = null;
           try {
  -            result = EsqlHelper.getStringOrClob(set,set.findColumn(column));
  +            result = EsqlHelper.getStringOrClob(set,set.findColumn(column), defaultString);
           } catch (Exception e) {
               throw new RuntimeException("Error getting clob data: " + e.getMessage());
           }
  @@ -153,10 +156,11 @@
   
       /** returns Unicode encoded string from CLOB or String column 
        */
  -    public final static String getStringOrClob(ResultSet set, int column) throws java.lang.Exception {
  +    public final static String getStringOrClob(ResultSet set, int column, String defaultString) throws java.lang.Exception {
           
           Reader reader = null;
           char[] buffer = null;
  +	String result = null;
       
           try {
               if (set.getMetaData().getColumnType(column)==java.sql.Types.CLOB) {
  @@ -168,23 +172,29 @@
                   reader.close();
                   if (reader != null)
                       reader.close();
  -                if (buffer == null)
  -                    return "";
  -                return new String(buffer);
  +		if(buffer != null) result = new String(buffer);
  +		else if(defaultString != null && !defaultString.equals("_null_"))
  +		    result = defaultString;
  +		else result = null;
               } else {           
  -                return set.getString(column);
  +                result = set.getString(column);
  +		if(result == null &&
  +		   defaultString != null && !defaultString.equals("_null_"))
  +		    result = defaultString;
               }
           } catch ( Exception e) {
               throw new RuntimeException("Error getting clob data: " + e.getMessage());
           }
  +	return result;
       }
   
       /** returns Unicode encoded string from CLOB or String column 
        */
  -    public final static String getStringOrClob(CallableStatement cs, int column) throws java.lang.Exception {
  +    public final static String getStringOrClob(CallableStatement cs, int column, String defaultString) throws java.lang.Exception {
           
           Reader reader = null;
           char[] buffer = null;
  +	String result = null;
       
           try {
               Clob dbClob = cs.getClob(column);
  @@ -195,22 +205,24 @@
               reader.close();
               if (reader != null)
                   reader.close();
  -            if (buffer == null)
  -                return "";
  -            return new String(buffer);
  +	    if(buffer != null) result = new String(buffer);
  +	    else if(defaultString != null && !defaultString.equals("_null_"))
  +		result = defaultString;
  +	    else result = null;
           } catch ( Exception e) {
               throw new RuntimeException("Error getting clob data: " + e.getMessage());
           }
  +	return result;
       }
   
   
       /** returns ascii string from CLOB or String column 
        */
  -      public final static String getAscii(ResultSet set, String column) throws RuntimeException {
  +      public final static String getAscii(ResultSet set, String column, String defaultString) throws RuntimeException {
   
             String result = null;
             try {
  -              result = EsqlHelper.getAscii(set,set.findColumn(column));
  +              result = EsqlHelper.getAscii(set,set.findColumn(column),defaultString);
             } catch (Exception e) {
                 throw new RuntimeException("Error getting clob data: " + e.getMessage());
             }
  @@ -220,7 +232,7 @@
   
       /** returns ascii string from CLOB or String column 
        */
  -      public final static String getAscii(ResultSet set, int column) {
  +      public final static String getAscii(ResultSet set, int column, String defaultString) {
           InputStream asciiStream = null;
           String result = null;
   
  @@ -233,9 +245,15 @@
                   buffer = new byte[length];
                   asciiStream.read(buffer);
                   asciiStream.close();
  -                result = (buffer!=null? new String(buffer) : null);
  +		if(buffer != null) result = new String(buffer);
  +		else if(defaultString != null && !defaultString.equals("_null_"))
  +		    result = defaultString;
  +		else result = null;
               } else {
                   result = set.getString(column);
  +		if(result == null &&
  +                   defaultString != null && !defaultString.equals("_null_"))
  +		    result = defaultString;
               }
           } catch (Exception e) {
               throw new RuntimeException("Error getting clob data: " + e.getMessage());
  @@ -250,7 +268,7 @@
   
       /** returns ascii string from CLOB or String column 
        */
  -    public final static String getAscii(CallableStatement cs, int column) {
  +    public final static String getAscii(CallableStatement cs, int column, String defaultString) {
           InputStream asciiStream = null;
           String result = null;
   
  @@ -262,7 +280,10 @@
               buffer = new byte[length];
               asciiStream.read(buffer);
               asciiStream.close();
  -            result = (buffer!=null? new String(buffer) : null);
  +	    if(buffer != null) result = new String(buffer);
  +	    else if(defaultString != null && !defaultString.equals("_null_"))
  +		result = defaultString;
  +	    else result = null;
           } catch (Exception e) {
               throw new RuntimeException("Error getting clob data: " + e.getMessage());
           } finally {
  @@ -274,7 +295,7 @@
           return result;
         }
   
  -      public final static String getStringFromByteArray(byte[] bytes, String encoding) {
  +      public final static String getStringFromByteArray(byte[] bytes, String encoding, String defaultString) {
           if (bytes != null) {
               try {
                   return new String(bytes,encoding);
  @@ -283,7 +304,9 @@
               }
           }
           else {
  -            return("");
  +	    if(defaultString != null && !defaultString.equals("_null_"))
  +		  return defaultString;
  +            else return null; /* before was "" but null is more consequent */
           }
         }
   
  
  
  
  1.3       +18 -6     xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/components/language/markup/xsp/java/esql.xsl
  
  Index: esql.xsl
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/components/language/markup/xsp/java/esql.xsl,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- esql.xsl	6 Nov 2002 18:18:30 -0000	1.2
  +++ esql.xsl	17 Nov 2002 18:00:04 -0000	1.3
  @@ -876,12 +876,24 @@
   
   <xspdoc:desc>returns the value of the given column as unicode string (column can be string or clob</xspdoc:desc>
   <xsl:template match="esql:row-results//esql:get-clob|esql:call-results//esql:get-clob" name="get-clob">
  -	<xsp:expr>EsqlHelper.getStringOrClob(<xsl:call-template name="get-resultset"/>,<xsl:call-template name="get-column"/>)</xsp:expr>
  +  <xsl:param name="null">
  +   <xsl:choose>
  +    <xsl:when test="@null"><xsl:value-of select="@null"/></xsl:when>
  +    <xsl:otherwise>_null_</xsl:otherwise>
  +   </xsl:choose>
  +  </xsl:param>
  +  <xsp:expr>EsqlHelper.getStringOrClob(<xsl:call-template name="get-resultset"/>,<xsl:call-template name="get-column"/>, "<xsl:value-of select="$null"/>")</xsp:expr>
   </xsl:template>
   
   <xspdoc:desc>returns the value of the given column as a clob as ascii string with optinal encoding</xspdoc:desc>
   <xsl:template match="esql:row-results//esql:get-ascii|esql:call-results//esql:get-ascii">
  -  <xsp:expr>EsqlHelper.getAscii(<xsl:call-template name="get-resultset"/>, <xsl:call-template name="get-column"/>)</xsp:expr>
  +  <xsl:param name="null">
  +   <xsl:choose>
  +    <xsl:when test="@null"><xsl:value-of select="@null"/></xsl:when>
  +    <xsl:otherwise>_null_</xsl:otherwise>
  +   </xsl:choose>
  +  </xsl:param>
  +  <xsp:expr>EsqlHelper.getAscii(<xsl:call-template name="get-resultset"/>, <xsl:call-template name="get-column"/>, "<xsl:value-of select="$null"/>")</xsp:expr>
   </xsl:template>
   
    <xspdoc:desc>returns the value of the given column interpeted as an xml fragment.
  @@ -1088,11 +1100,11 @@
     </xsl:variable>
     <xsl:choose>
       <xsl:when test="$encoding = 'default'">
  -      EsqlHelper.getAscii(<xsl:value-of select="$resultset"/>,<xsl:value-of select="$column-spec"/>)
  +      EsqlHelper.getAscii(<xsl:value-of select="$resultset"/>,<xsl:value-of select="$column-spec"/>,"<xsl:value-of select="$null"/>")
       </xsl:when>
       <xsl:otherwise>
         EsqlHelper.getStringFromByteArray(<xsl:value-of select="$resultset"/>.getBytes
  -        (<xsl:value-of select="$column-spec"/>), <xsl:value-of select="$encoding"/>)
  +        (<xsl:value-of select="$column-spec"/>), <xsl:value-of select="$encoding"/>,"<xsl:value-of select="$null"/>")
       </xsl:otherwise>
     </xsl:choose>
   </xsl:template>
  
  
  

----------------------------------------------------------------------
In case of troubles, e-mail:     webmaster@xml.apache.org
To unsubscribe, e-mail:          cocoon-cvs-unsubscribe@xml.apache.org
For additional commands, e-mail: cocoon-cvs-help@xml.apache.org