haul        2002/10/18 07:04:28

  Added:       src/blocks/hsqldb/java/org/apache/cocoon/components/hsqldb
                        Server.java ServerImpl.java
               src/blocks/hsqldb/conf hsqldb.xconf hsqldb.xroles
               src/blocks/databases/java/org/apache/cocoon/util
                        JDBCTypeConversions.java JDBCxlobHelper.java
               src/blocks/databases/java/org/apache/cocoon/transformation
                        SQLTransformer.java
               src/blocks/databases/java/org/apache/cocoon/reading
                        DatabaseReader.java
               
src/blocks/databases/java/org/apache/cocoon/components/modules/input
                        CollectionMetaModule.java
               
src/blocks/databases/java/org/apache/cocoon/components/modules/database
                        AbstractAutoIncrementModule.java
                        AutoIncrementModule.java
                        HsqlIdentityAutoIncrementModule.java
                        IfxSerialAutoIncrementModule.java
                        ManualAutoIncrementModule.java
                        MysqlAutoIncrementModule.java
                        PgsqlAutoIncrementModule.java package.html
               
src/blocks/databases/java/org/apache/cocoon/components/language/markup/xsp
                        EsqlConnection.java EsqlConnectionCocoon2.java
                        EsqlHelper.java EsqlQuery.java
               
src/blocks/databases/java/org/apache/cocoon/components/language/markup/xsp/java
                        esql.xsl
               src/blocks/databases/java/org/apache/cocoon/acting
                        AbstractDatabaseAction.java DatabaseAddAction.java
                        DatabaseAuthenticatorAction.java
                        DatabaseCookieAuthenticatorAction.java
                        DatabaseDeleteAction.java DatabaseSelectAction.java
                        DatabaseUpdateAction.java
                        DbXMLAuthenticatorAction.java OraAddAction.java
                        OraUpdateAction.java
               src/blocks/databases/java/org/apache/cocoon/acting/modular
                        DatabaseAction.java DatabaseAddAction.java
                        DatabaseDeleteAction.java DatabaseQueryAction.java
                        DatabaseSelectAction.java DatabaseUpdateAction.java
                        package.html
               src/blocks/databases/conf databases-trans.xmap
                        datasources.xconf db-modules-input.xconf
                        db-modules.xconf db-modules.xroles esql.xconf
  Log:
  New block for database related stuff
  New block for hsqldb related stuff
  Minor changes to module related stuff (i.e. defaults changed
  to new names)
  Minor additions to modules
  New ChainMetaModule implementing chaining as discussed on list
  
  Not finished:
  - database samples not yet in block
  - change to InputModule Interface to use Iterator instead of Enumeration
  - other minor tweaks and corrections
  
  Revision  Changes    Path
  1.1                  
xml-cocoon2/src/blocks/hsqldb/java/org/apache/cocoon/components/hsqldb/Server.java
  
  Index: Server.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
      [EMAIL PROTECTED]
  
   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  <[EMAIL PROTECTED]>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  package org.apache.cocoon.components.hsqldb;
  
  import org.apache.avalon.framework.component.Component;
  
  /**
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Davanum Srinivas</a>
   * @version CVS $Id: Server.java,v 1.1 2002/10/18 14:04:26 haul Exp $
   */
  public interface Server extends Component {
      String ROLE = Server.class.getName();
  }
  
  
  
  1.1                  
xml-cocoon2/src/blocks/hsqldb/java/org/apache/cocoon/components/hsqldb/ServerImpl.java
  
  Index: ServerImpl.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
      [EMAIL PROTECTED]
  
   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  <[EMAIL PROTECTED]>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  package org.apache.cocoon.components.hsqldb;
  
  import org.apache.avalon.framework.activity.Startable;
  import org.apache.avalon.framework.context.Context;
  import org.apache.avalon.framework.context.ContextException;
  import org.apache.avalon.framework.context.Contextualizable;
  import org.apache.avalon.framework.logger.AbstractLogEnabled;
  import org.apache.avalon.framework.parameters.Parameters;
  import org.apache.avalon.framework.parameters.Parameterizable;
  import org.apache.avalon.framework.thread.ThreadSafe;
  import org.apache.cocoon.Constants;
  
  import java.io.File;
  import java.io.IOException;
  import java.net.MalformedURLException;
  import java.sql.SQLException;
  import java.sql.Connection;
  import java.sql.DriverManager;
  import java.sql.Statement;
  import java.util.Enumeration;
  
  /**
   * This class runs an instance of HSQLDB Server.
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Davanum Srinivas</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Vadim Gritsenko</a>
   * @version CVS $Id: ServerImpl.java,v 1.1 2002/10/18 14:04:26 haul Exp $
   */
  public class ServerImpl extends AbstractLogEnabled
      implements Server,
                 Parameterizable,
                 Contextualizable,
                 ThreadSafe,
                 Runnable,
                 Startable {
  
      /** Port which HSQLDB server will listen to */
      private String port;
  
      /** Arguments for running the server */
      private String arguments[] = new String[8];
  
      /** Check if the server has already been started */
      private boolean started = false;
  
      /**
       * Initialize the ServerImpl.
       * A few options can be used :
       * <UL>
       *  <LI>port = port where the server is listening</LI>
       *  <LI>silent = display all queries</LI>
       *  <LI>trace = print JDBC trace messages</LI>
       * </UL>
       */
      public void parameterize(Parameters params)  {
          this.getLogger().debug("Parameterize ServerImpl");
  
          arguments[0] = "-port";
          arguments[1] = this.port = params.getParameter("port", "9002");
          arguments[2] = "-silent";
          arguments[3] = params.getParameter("silent","true");
          arguments[4] = "-trace";
          arguments[5] = params.getParameter("trace","false");
          arguments[4] = "-no_system_exit";
          arguments[5] = "true";
          if (this.getLogger().isDebugEnabled()) {
              this.getLogger().debug("Configure ServerImpl with port: " + 
arguments[1]
                      + ", silent: " + arguments[3]
                      + ", trace: " +arguments[5]);
          }
      }
  
      /** Contextualize this class */
      public void contextualize(Context context) throws ContextException {
          org.apache.cocoon.environment.Context ctx =
                  (org.apache.cocoon.environment.Context) 
context.get(Constants.CONTEXT_ENVIRONMENT_CONTEXT);
          // test if we are running inside a WAR file
          final String dbPath = ctx.getRealPath("/WEB-INF/db");
          if (dbPath == null) {
              throw new ContextException("The hsqldb cannot be used inside a 
WAR file.");
          }
  
          try {
              arguments[6] = "-database";
              arguments[7] = new File(dbPath).getCanonicalPath();
              arguments[7] += File.separator + "cocoondb";
              getLogger().debug("database is " + arguments[7]);
          } catch (MalformedURLException e) {
              getLogger().error("MalformedURLException - Could not get database 
directory ", e);
          } catch (IOException e) {
              getLogger().error("IOException - Could not get database directory 
", e);
          }
      }
  
      /** Start the server */
      public void start() {
          if (!started) {
              // FIXME (VG): This dirty hack here is till shutdown issue is 
resolved
              File file = new File(arguments[7] + ".backup");
              if (file.exists() && file.delete()) {
                  getLogger().info("HSQLDB backup file has been deleted.");
              }
  
              Thread server = new Thread(this);
              this.getLogger().debug("Intializing hsqldb server thread");
              server.setPriority(Thread.currentThread().getPriority());
              server.setDaemon(true);
              server.setName("hsqldb server");
              server.start();
          }
      }
  
      /** Stop the server */
      public void stop() {
          if (started) {
              try {
                  getLogger().debug("Shutting down HSQLDB");
                  Connection connection = 
DriverManager.getConnection("jdbc:hsqldb:hsql://localhost:" + this.port, "sa", 
"");
                  Statement statement = connection.createStatement();
                  statement.executeQuery("SHUTDOWN");
                  try {
                      connection.close();
                  } catch (SQLException e) {
                      getLogger().debug("Shutting down HSQLDB: Ignoring 
exception: " + e);
                  }
              } catch (Exception e){
                  getLogger().error("Error while shutting down HSQLDB", e);
              }
              getLogger().debug("Shutting down HSQLDB: Done");
          }
      }
  
      public void run() {
          if(!started) {
              started = true;
  
              try {
                  getLogger().debug("HSQLDB Server arguments are as follows:");
                  for(int i=0;i<8;i++) {
                      getLogger().debug(i + " : " + arguments[i]);
                  }
  
                  org.hsqldb.Server.main(arguments);
              } catch(Exception e){
                  getLogger().error("Got exception", e);
              } finally {
                  started = false;
              }
          }
      }
  }
  
  
  
  1.1                  xml-cocoon2/src/blocks/hsqldb/conf/hsqldb.xconf
  
  Index: hsqldb.xconf
  ===================================================================
  <?xml version="1.0"?>
  
  <xconf xpath="/cocoon" unless="hsqldb-server" insert-before="xml-parser">
    <!-- HSQLDB Server for samples:
      Comment this section out if you don't care about the samples.
          port   : number      port where the server is listening
          silent : true/false  display all queries
          trace  : true/false  display JDBC trace messages
    -->
    <hsqldb-server class="org.apache.cocoon.components.hsqldb.ServerImpl"
                   logger="core.hsqldb-server"
                   pool-max="1" pool-min="1">
       <parameter name="port" value="9002"/>
       <parameter name="silent" value="true"/>
       <parameter name="trace" value="false"/>
    </hsqldb-server>
  
  </xconf>
  
  
  
  1.1                  xml-cocoon2/src/blocks/hsqldb/conf/hsqldb.xroles
  
  Index: hsqldb.xroles
  ===================================================================
  <?xml version="1.0"?>
  <xroles xpath="/role-list" unless="[EMAIL 
PROTECTED]'org.apache.cocoon.components.hsqldb.Server']">
  
    <role name="org.apache.cocoon.components.hsqldb.Server" 
shorthand="hsqldb-server" 
default-class="org.apache.cocoon.components.hsqldb.ServerImpl"/>
  </xroles>
  
  
  
  1.1                  
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/util/JDBCTypeConversions.java
  
  Index: JDBCTypeConversions.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
      [EMAIL PROTECTED]
  
   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  <[EMAIL PROTECTED]>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  package org.apache.cocoon.util;
  
  import java.io.*;
  import java.sql.PreparedStatement;
  import java.sql.Statement;
  import java.sql.ResultSet;
  import java.sql.SQLException;
  import java.sql.Timestamp;
  import java.sql.Time;
  import java.sql.Date;
  import java.sql.Array;
  import java.sql.Types;
  import java.sql.Clob;
  import java.sql.Struct;
  import java.math.BigDecimal;
  import java.util.Map;
  import java.util.HashMap;
  import java.util.Collections;
  import java.text.DateFormat;
  import java.text.SimpleDateFormat;
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.configuration.ConfigurationException;
  import org.apache.excalibur.source.Source;
  
  
  /**
   * Provide some utility methods to read from JDBC result sets or store
   * them to JDBC statements. Largely copied from
   * org.apache.cocoon.acting.AbstractDatabaseAction.
   *
   */
  public class JDBCTypeConversions {
      public static final Map typeConstants;
  
      static {
          /** Initialize the map of type names to jdbc column types.
              Note that INTEGER, BLOB, and VARCHAR column types map to more than
              one type name. **/
          Map constants = new HashMap();
          constants.put("ascii", new Integer(Types.CLOB));
          constants.put("big-decimal", new Integer(Types.BIGINT));
          constants.put("binary", new Integer(Types.BLOB));
          constants.put("boolean", new Integer(Types.BIT));
          constants.put("byte", new Integer(Types.TINYINT));
          constants.put("string", new Integer(Types.VARCHAR));
          constants.put("date", new Integer(Types.DATE));
          constants.put("double", new Integer(Types.DOUBLE));
          constants.put("float", new Integer(Types.FLOAT));
          constants.put("int", new Integer(Types.INTEGER));
          constants.put("long", new Integer(Types.NUMERIC));
          constants.put("short", new Integer(Types.SMALLINT));
          constants.put("time", new Integer(Types.TIME));
          constants.put("time-stamp", new Integer(Types.TIMESTAMP));
          constants.put("array", new Integer(Types.ARRAY));
          constants.put("row", new Integer(Types.STRUCT));
          constants.put("object", new Integer(Types.OTHER));
          typeConstants = Collections.unmodifiableMap(constants);
      }
  
      /**
       * Converts an object to a JDBC type. This has just been started
       * and does not do much at the moment.
       *
       */
      public static Object convert(Object value, String jType) {
  
          Object object=null;
          if (jType.equalsIgnoreCase("string")) {
              if (value instanceof String) {
                  object = value;
              } else {
                  object = value.toString();
              }
          } else if (jType.equalsIgnoreCase("int")) {
              if (value instanceof String) {
                  object = Integer.decode((String)value);
              } else if (value instanceof Integer) {
                  object = value;
              } else {
                  //
              }
          } else if (jType.equalsIgnoreCase("long")) {
              if (value instanceof String) {
                  object = Long.decode((String)value);
              } else if (value instanceof Long) {
                  object = value;
              } else {
                  //
              }
          } else {
              // other types need parsing & creation
              //
          }
          return object;
      }
                      
        
  
      /**
       * Get the Statement column so that the results are mapped correctly.
       * (this has been copied from AbstractDatabaseAction and modified 
slightly)
       */
      public static Object getColumn(ResultSet set, Configuration column ) 
throws Exception {
  
          Integer type = (Integer) 
JDBCTypeConversions.typeConstants.get(column.getAttribute("type"));
          String dbcol = column.getAttribute("name");
          Object value = null;
  
          switch (type.intValue()) {
          case Types.CLOB:
              Clob dbClob = set.getClob(dbcol);
              int length = (int) dbClob.length();
              InputStream asciiStream = new 
BufferedInputStream(dbClob.getAsciiStream());
              byte[] buffer = new byte[length];
              asciiStream.read(buffer);
              String str = new String(buffer);
              asciiStream.close();
              value = str;
              break;
          case Types.BIGINT:
              value = set.getBigDecimal(dbcol);
              break;
          case Types.TINYINT:
              value = new Byte(set.getByte(dbcol));
              break;
          case Types.VARCHAR:
              value  = set.getString(dbcol);
              break;
          case Types.DATE:
              value = set.getDate(dbcol);
              break;
          case Types.DOUBLE:
              value = new Double(set.getDouble(dbcol));
              break;
          case Types.FLOAT:
              value = new Float(set.getFloat(dbcol));
              break;
          case Types.INTEGER:
              value = new Integer(set.getInt(dbcol));
              break;
          case Types.NUMERIC:
              value = new Long(set.getLong(dbcol));
              break;
          case Types.SMALLINT:
              value = new Short(set.getShort(dbcol));
              break;
          case Types.TIME:
              value = set.getTime(dbcol);
              break;
          case Types.TIMESTAMP:
              value = set.getTimestamp(dbcol);
              break;
          case Types.ARRAY:
              value = set.getArray(dbcol); // new Integer(set.getInt(dbcol));
              break;
          case Types.BIT:
              value = new Integer(set.getInt(dbcol));
              break;
          case Types.CHAR:
              value = new Integer(set.getInt(dbcol));
              break;
          case Types.STRUCT:
              value = (Struct) set.getObject(dbcol);
              break;
          case Types.OTHER:
              value = set.getObject(dbcol);
              break;
  
          default:
              // The blob types have to be requested separately, via a Reader.
              value = "";
              break;
          }
  
          return value;
      }
  
  
      /**
       * Set the Statement column so that the results are mapped correctly.
       *
       * @param statement the prepared statement
       * @param position the position of the column
       * @param request the request
       * @param entry the configuration object
       * @param param the name of the request parameter
       * @param value the value of the column
       * @param rowIndex the index of the current row for manyrows inserts
       */
      public static void setColumn(PreparedStatement statement, int position, 
Object value, Integer typeObject) throws Exception {
          if (value instanceof String) {
              value = ((String) value).trim();
          }
          if (typeObject == null) {
              throw new SQLException("Can't set column because the type is 
unrecognized");
          }
          if (value == null) {
              /** If the value is null, set the column value null and return **/
              statement.setNull(position, typeObject.intValue());
              return;
          }
          if ("".equals(value)) {
              switch (typeObject.intValue()) {
                  case Types.CHAR:
                  case Types.CLOB:
                  case Types.VARCHAR:
                      /** If the value is an empty string and the column is
                          a string type, we can continue **/
                      break;
                  default:
                      /** If the value is an empty string and the column
                          is something else, we treat it as a null value **/
                      statement.setNull(position, typeObject.intValue());
                      return;
              }
          }
  
          File file = null;
  
          switch (typeObject.intValue()) {
              case Types.CLOB:
                  int length = -1;
                  InputStream asciiStream = null;
  
                  if (value instanceof File) {
                      File asciiFile = (File) value;
                      asciiStream = new BufferedInputStream(new 
FileInputStream(asciiFile));
                      length = (int) asciiFile.length();
                  } else if (value instanceof JDBCxlobHelper) {
                      asciiStream = ((JDBCxlobHelper) value).inputStream;
                      length = ((JDBCxlobHelper) value).length;
                  } else if (value instanceof Source) {
                      asciiStream = ((Source) value).getInputStream();
                      length = (int)((Source) value).getContentLength();
                  } else {
                      String asciiText = (String) value;
                      asciiStream = new BufferedInputStream(new 
ByteArrayInputStream(asciiText.getBytes()));
                      length = asciiText.length();
                  }
  
                  statement.setAsciiStream(position, asciiStream, length);
                  break;
              case Types.BIGINT:
                  BigDecimal bd = null;
  
                  if (value instanceof BigDecimal) {
                      bd = (BigDecimal) value;
                  } else {
                      bd = new BigDecimal((String) value);
                  }
  
                  statement.setBigDecimal(position, bd);
                  break;
              case Types.TINYINT:
                  Byte b = null;
  
                  if (value instanceof Byte) {
                      b = (Byte) value;
                  } else {
                      b = new Byte((String) value);
                  }
  
                  statement.setByte(position, b.byteValue());
                  break;
              case Types.DATE:
                  Date d = null;
  
                  if (value instanceof Date) {
                      d = (Date) value;
                  } else if (value instanceof java.util.Date) {
                      d = new Date(((java.util.Date) value).getTime());
                  }
  
                  statement.setDate(position, d);
                  break;
              case Types.DOUBLE:
                  Double db = null;
  
                  if (value instanceof Double) {
                      db = (Double) value;
                  } else {
                      db = new Double((String) value);
                  }
  
                  statement.setDouble(position, db.doubleValue());
                  break;
              case Types.FLOAT:
                  Float f = null;
  
                  if (value instanceof Float) {
                      f = (Float) value;
                  } else {
                      f = new Float((String) value);
                  }
  
                  statement.setFloat(position, f.floatValue());
                  break;
              case Types.NUMERIC:
                  Long l = null;
  
                  if (value instanceof Long) {
                      l = (Long) value;
                  } else {
                      l = new Long((String) value);
                  }
  
                  statement.setLong(position, l.longValue());
                  break;
              case Types.SMALLINT:
                  Short s = null;
  
                  if (value instanceof Short) {
                      s = (Short) value;
                  } else {
                      s = new Short((String) value);
                  }
  
                  statement.setShort(position, s.shortValue());
                  break;
              case Types.TIME:
                  Time t = null;
  
                  if (value instanceof Time) {
                      t = (Time) value;
                  }
  
                  statement.setTime(position, t);
                  break;
              case Types.TIMESTAMP:
                  Timestamp ts = null;
  
                  if (value instanceof Time) {
                      ts = (Timestamp) value;
                  }
  
                  statement.setTimestamp(position, ts);
                  break;
              case Types.ARRAY:
                  statement.setArray(position, (Array) value); // no way to 
convert string to array
                  break;
              case Types.STRUCT:
              case Types.OTHER:
                  statement.setObject(position, value);
                  break;
              case Types.LONGVARBINARY:
                  statement.setTimestamp(position, new Timestamp((new 
java.util.Date()).getTime()));
              case Types.VARCHAR:
                  statement.setString(position, (String) value);
                  break;
              case Types.BLOB:
                  if (value instanceof JDBCxlobHelper) {
                      statement.setBinaryStream(position, 
((JDBCxlobHelper)value).inputStream, ((JDBCxlobHelper)value).length);
                  } else if (value instanceof Source){
                      statement.setBinaryStream(position, 
((Source)value).getInputStream(), (int)((Source)value).getContentLength());
                  } else {
                      if (value instanceof File) {
                          file = (File)value;
                      } else if (value instanceof String) {
                          file = new File((String)value);
                      } else {
                          throw new SQLException("Invalid type for blob: 
"+value.getClass().getName());
                      }
                      //InputStream input = new BufferedInputStream(new 
FileInputStream(file));
                      FileInputStream input = new FileInputStream(file);
                      statement.setBinaryStream(position, input, 
(int)file.length());
                  }
                  break;
              case Types.INTEGER:
                  Integer i = null;
                  if (value instanceof Integer) {
                      i = (Integer) value;
                  } else if (value instanceof java.lang.Number) {
                      i = new Integer(((java.lang.Number) value).intValue());
                  } else {
                      i = new Integer(value.toString());
                  }
                  statement.setInt(position, i.intValue());
                  break;
              case Types.BIT:
                  Boolean bo = null;
                  if (value instanceof Boolean) {
                      bo = (Boolean) value;
                  } else if (value instanceof java.lang.Number) {
                      bo = new Boolean(((java.lang.Number) 
value).intValue()==1);
                  } else {
                      bo = new Boolean(value.toString());
                  }
                  statement.setBoolean(position, bo.booleanValue());
                  break;
                      
              default:
                  throw new SQLException("Impossible exception - invalid type 
");
          }
      }
  
  
  }
  
  
  
  1.1                  
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/util/JDBCxlobHelper.java
  
  Index: JDBCxlobHelper.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
      [EMAIL PROTECTED]
  
   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  <[EMAIL PROTECTED]>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  package org.apache.cocoon.util;
  
  import java.io.InputStream;
  
  /**
   * Helper to pass a length plus an InputStream to JDBCTypeConversions
   * to insert BLOB (setBinaryStream) or CLOB (setAsciiStream) via data using
   * org.apache.cocoon.acting.modular.DatabaseAction. Create an input module
   * that returns an instance of this class and use that in your database.xml
   *
   */
  public class JDBCxlobHelper {
      public int length = 0;
      public InputStream inputStream = null;
  }
  
  
  
  
  1.1                  
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/transformation/SQLTransformer.java
  
  Index: SQLTransformer.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
      [EMAIL PROTECTED]
  
   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  <[EMAIL PROTECTED]>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  package org.apache.cocoon.transformation;
  
  import org.apache.avalon.excalibur.datasource.DataSourceComponent;
  import org.apache.avalon.excalibur.xml.Parser;
  import org.apache.avalon.framework.activity.Disposable;
  import org.apache.avalon.framework.component.*;
  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.parameters.Parameters;
  import org.apache.cocoon.ProcessingException;
  import org.apache.cocoon.components.sax.XMLDeserializer;
  import org.apache.cocoon.components.sax.XMLSerializer;
  import org.apache.cocoon.environment.SourceResolver;
  import org.apache.cocoon.util.Tokenizer;
  import org.apache.cocoon.xml.IncludeXMLConsumer;
  import org.apache.avalon.framework.logger.Logger;
  import org.xml.sax.Attributes;
  import org.xml.sax.InputSource;
  import org.xml.sax.Locator;
  import org.xml.sax.SAXException;
  import org.xml.sax.helpers.AttributesImpl;
  
  import java.io.IOException;
  import java.io.StringReader;
  import java.lang.reflect.Field;
  import java.sql.*;
  import java.util.*;
  import javax.xml.transform.OutputKeys;
  
  /**
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Carsten Ziegeler</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Donald Ball</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Giacomo Pati</a>
   *         (PWR Organisation & Entwicklung)
   * @author <a href="mailto:[EMAIL PROTECTED]">Sven Beauprez</a>
   * @version CVS $Id: SQLTransformer.java,v 1.1 2002/10/18 14:04:26 haul Exp $
   */
  
  public class SQLTransformer
    extends AbstractSAXTransformer
    implements Composable, Disposable, Configurable {
  
      /** The SQL namespace **/
      public static final String NAMESPACE = "http://apache.org/cocoon/SQL/2.0";;
  
      /** The SQL namespace element names **/
      public static final String MAGIC_EXECUTE_QUERY = "execute-query";
      public static final String MAGIC_CONNECTION = "use-connection";
      public static final String MAGIC_DBURL = "dburl";
      public static final String MAGIC_USERNAME = "username";
      public static final String MAGIC_PASSWORD = "password";
      public static final String MAGIC_NR_OF_ROWS = "show-nr-of-rows";
      public static final String MAGIC_QUERY = "query";
      public static final String MAGIC_VALUE = "value";
      public static final String MAGIC_DOC_ELEMENT = "doc-element";
      public static final String MAGIC_ROW_ELEMENT = "row-element";
      public static final String MAGIC_IN_PARAMETER = "in-parameter";
      public static final String MAGIC_IN_PARAMETER_NR_ATTRIBUTE = "nr";
      public static final String MAGIC_IN_PARAMETER_VALUE_ATTRIBUTE = "value";
      public static final String MAGIC_OUT_PARAMETER = "out-parameter";
      public static final String MAGIC_OUT_PARAMETER_NAME_ATTRIBUTE = "name";
      public static final String MAGIC_OUT_PARAMETER_NR_ATTRIBUTE = "nr";
      public static final String MAGIC_OUT_PARAMETER_TYPE_ATTRIBUTE = "type";
      public static final String MAGIC_ESCAPE_STRING = "escape-string";
      public static final String MAGIC_ERROR = "error";
  
      public static final String MAGIC_NS_URI_ELEMENT = "namespace-uri";
      public static final String MAGIC_NS_PREFIX_ELEMENT = "namespace-prefix";
  
      public static final String MAGIC_ANCESTOR_VALUE = "ancestor-value";
      public static final String MAGIC_ANCESTOR_VALUE_LEVEL_ATTRIBUTE = "level";
      public static final String MAGIC_ANCESTOR_VALUE_NAME_ATTRIBUTE = "name";
      public static final String MAGIC_SUBSTITUTE_VALUE = "substitute-value";
      public static final String MAGIC_SUBSTITUTE_VALUE_NAME_ATTRIBUTE = "name";
      public static final String MAGIC_NAME_ATTRIBUTE = "name";
      public static final String MAGIC_STORED_PROCEDURE_ATTRIBUTE = 
"isstoredprocedure";
      public static final String MAGIC_UPDATE_ATTRIBUTE = "isupdate";
  
      /** The states we are allowed to be in **/
      protected static final int STATE_OUTSIDE = 0;
      protected static final int STATE_INSIDE_EXECUTE_QUERY_ELEMENT = 1;
      protected static final int STATE_INSIDE_VALUE_ELEMENT = 2;
      protected static final int STATE_INSIDE_QUERY_ELEMENT = 3;
      protected static final int STATE_INSIDE_ANCESTOR_VALUE_ELEMENT = 4;
      protected static final int STATE_INSIDE_SUBSTITUTE_VALUE_ELEMENT = 5;
      protected static final int STATE_INSIDE_IN_PARAMETER_ELEMENT = 6;
      protected static final int STATE_INSIDE_OUT_PARAMETER_ELEMENT = 7;
      protected static final int STATE_INSIDE_ESCAPE_STRING = 8;
  
      //
      // Configuration
      //
  
      /** Is the old-driver turned on? (default is off) */
      private boolean oldDriver = false;
  
      /** How many connection attempts to do? (default is 5 times) */
      private int connectAttempts = 5;
  
      /** How long wait between connection attempts? (default is 5000 ms) */
      private int connectWaittime = 5;
  
      //
      // State
      //
  
      /** The list of queries that we're currently working on **/
      protected Vector queries;
  
      /** The offset of the current query in the queries list **/
      protected int current_query_index;
  
      /** The current state of the event receiving FSM **/
      protected int current_state;
  
      /** Check if nr of rows need to be written out. **/
      protected boolean showNrOfRows;
  
      /** Namespace prefix to output */
      protected String outPrefix;
  
      /** Namespace uri to output */
      protected String outUri;
  
      /** The prefix of our namespace to listen to */
      protected String inPrefix;
  
      /** The database selector */
      protected ComponentSelector dbSelector;
  
      /** The format for serializing xml */
      protected Properties format;
  
      protected XMLSerializer compiler;
      protected XMLDeserializer interpreter;
      protected Parser parser;
  
      /**
       * Constructor
       */
      public SQLTransformer() {
          // FIXME (CZ) We have to get the correct encoding from
          // somewhere else (XML Serializer?)
          this.format = new Properties();
          this.format.put(OutputKeys.METHOD, "text");
          this.format.put(OutputKeys.ENCODING, "ISO-8859-1");
          this.format.put(OutputKeys.OMIT_XML_DECLARATION, "yes");
          this.namespaceURI = NAMESPACE;
      }
  
      /**
       * Composable
       */
      public void compose( ComponentManager manager ) {
          super.compose(manager);
          this.queries = new Vector();
          try {
              this.dbSelector = (ComponentSelector) manager.lookup( 
DataSourceComponent.ROLE + "Selector" );
          } catch ( ComponentException cme ) {
              this.getLogger().warn( "Could not get the DataSource Selector", 
cme );
          }
      }
  
      /**
       * Recycle this component
       */
      public void recycle() {
          super.recycle();
          this.queries.clear();
          this.outUri = null;
          this.inPrefix = null;
          this.outPrefix = null;
          this.manager.release(this.parser);
          this.parser = null;
          this.manager.release(this.compiler);
          this.compiler = null;
          this.manager.release(this.interpreter);
          this.interpreter = null;
      }
  
      /**
       * dispose
       */
      public void dispose() {
          if ( this.dbSelector != null ) {
              this.manager.release( (Component) this.dbSelector );
          }
      }
  
      /**
       * configure
       */
      public void configure( Configuration conf ) throws ConfigurationException 
{
          super.configure( conf );
          if ( conf != null ) {
              this.oldDriver = conf.getChild( "old-driver" ).getValueAsBoolean( 
false );
              if (this.getLogger().isDebugEnabled()) {
                  this.getLogger().debug( "old-driver is " + this.oldDriver + " 
for " + this );
              }
  
              this.connectAttempts = 
conf.getChild("connect-attempts").getValueAsInteger(5);
              this.connectWaittime = 
conf.getChild("connect-waittime").getValueAsInteger(5000);
          }
      }
  
      /**
       * Setup for the current request
       */
      public void setup( SourceResolver resolver, Map objectModel,
                         String source, Parameters parameters )
      throws ProcessingException, SAXException, IOException {
          super.setup(resolver, objectModel, source, parameters);
          // setup instance variables
          this.current_query_index = -1;
          this.current_state = SQLTransformer.STATE_OUTSIDE;
  
          this.showNrOfRows = parameters.getParameterAsBoolean( 
SQLTransformer.MAGIC_NR_OF_ROWS, false );
          if ( this.getLogger().isDebugEnabled() ) {
              if ( this.parameters.getParameter( 
SQLTransformer.MAGIC_CONNECTION , null ) != null ) {
                  this.getLogger().debug( "CONNECTION: " + 
this.parameters.getParameter( SQLTransformer.MAGIC_CONNECTION , null ) );
              } else {
                  this.getLogger().debug( "DBURL: " + parameters.getParameter( 
SQLTransformer.MAGIC_DBURL, null ) );
                  this.getLogger().debug( "USERNAME: " + 
parameters.getParameter( SQLTransformer.MAGIC_USERNAME, null ) );
              }
              this.getLogger().debug( "DOC-ELEMENT: " + 
parameters.getParameter( SQLTransformer.MAGIC_DOC_ELEMENT, "rowset" ) );
              this.getLogger().debug( "ROW-ELEMENT: " + 
parameters.getParameter( SQLTransformer.MAGIC_ROW_ELEMENT, "row" ) );
              this.getLogger().debug( "NS-URI: " + parameters.getParameter( 
SQLTransformer.MAGIC_NS_URI_ELEMENT, NAMESPACE ) );
              this.getLogger().debug( "NS-PREFIX: " + parameters.getParameter( 
SQLTransformer.MAGIC_NS_PREFIX_ELEMENT, "" ) );
          }
     }
  
      /**
       * This will be the meat of SQLTransformer, where the query is run.
       */
      protected void executeQuery( int index )
      throws SAXException {
          if ( this.getLogger().isDebugEnabled() ) {
              this.getLogger().debug( "SQLTransformer executing query nr " + 
index );
          }
  
          this.outUri = getCurrentQuery().properties.getParameter( 
SQLTransformer.MAGIC_NS_URI_ELEMENT, NAMESPACE );
          this.outPrefix = getCurrentQuery().properties.getParameter( 
SQLTransformer.MAGIC_NS_PREFIX_ELEMENT, "" );
  
          if ( !"".equals( this.outUri ) ) {
              super.startPrefixMapping( this.outPrefix, this.outUri );
          }
  
          AttributesImpl attr = new AttributesImpl();
          Query query = (Query) queries.elementAt( index );
          boolean query_failure = false;
          try {
              try {
                  query.execute();
              } catch ( SQLException e ) {
                  if (this.getLogger().isDebugEnabled()) {
                      this.getLogger().debug( "SQLTransformer:.executeQuery() 
query.execute failed ", e );
                  }
                  AttributesImpl my_attr = new AttributesImpl();
                  this.start( query.rowset_name, my_attr );
                  this.start( MAGIC_ERROR, my_attr);
                  this.data( e.getMessage());
                  this.end( MAGIC_ERROR );
                  this.end( query.rowset_name );
                  query_failure = true;
              }
              if ( !query_failure ) {
  
                  if ( this.showNrOfRows ) {
                      attr.addAttribute( NAMESPACE, query.nr_of_rows, 
query.nr_of_rows, "CDATA",
                         String.valueOf( query.getNrOfRows() ) );
                  }
                  String name = query.getName();
                  if ( name != null ) {
                      attr.addAttribute( NAMESPACE, query.name_attribute, 
query.name_attribute, "CDATA",
                         name );
                  }
                  this.start( query.rowset_name, attr );
                  attr = new AttributesImpl();
  
                  if ( !query.isStoredProcedure() ) {
                      while ( query.next() ) {
                          this.start( query.row_name, attr );
                          query.serializeRow(this.manager);
                          if ( index + 1 < queries.size() ) {
                              executeQuery( index + 1 );
                          }
                          this.end( query.row_name );
                      }
                  } else {
                      query.serializeStoredProcedure(this.manager);
                  }
  
                  this.end( query.rowset_name );
              }
          } catch ( SQLException e ) {
              if (this.getLogger().isDebugEnabled()) {
                  getLogger().debug( "SQLTransformer.executeQuery()", e );
              }
              throw new SAXException( e );
          } finally {
              try {
                  query.close();
              } catch ( SQLException e ) {
                  getLogger().warn( "SQLTransformer: Could not close JDBC 
connection", e );
              }
          }
          if ( !"".equals( this.outUri ) ) {
              super.endPrefixMapping( this.outPrefix );
          }
      }
  
      protected static void throwIllegalStateException( String message ) {
          throw new IllegalStateException( "SQLTransformer: " + message );
      }
  
      protected void startExecuteQueryElement() {
          switch ( current_state ) {
              case SQLTransformer.STATE_OUTSIDE:
              case SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_ELEMENT:
                  current_query_index = queries.size();
                  Query query = new Query( this, current_query_index );
                  queries.addElement( query );
                  current_state = 
SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_ELEMENT;
                  break;
              default:
                  throwIllegalStateException( "Not expecting a start execute 
query element" );
          }
      }
  
      protected void startValueElement( String name )
      throws SAXException {
          switch ( current_state ) {
              case SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_ELEMENT:
                  this.stack.push(name);
                  this.startTextRecording();
                  current_state = SQLTransformer.STATE_INSIDE_VALUE_ELEMENT;
                  break;
              default:
                  throwIllegalStateException( "Not expecting a start value 
element: " +
                                              name );
          }
      }
  
      protected void startQueryElement( Attributes attributes )
      throws SAXException {
          switch ( current_state ) {
              case SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_ELEMENT:
                  this.startSerializedXMLRecording(format);
                  Query q = getCurrentQuery();
                  current_state = SQLTransformer.STATE_INSIDE_QUERY_ELEMENT;
                  String isupdate =
                          attributes.getValue( "", 
SQLTransformer.MAGIC_UPDATE_ATTRIBUTE );
                  if ( isupdate != null && !isupdate.equalsIgnoreCase( "false" 
) )
                      q.setUpdate( true );
                  String isstoredprocedure =
                          attributes.getValue( "", 
SQLTransformer.MAGIC_STORED_PROCEDURE_ATTRIBUTE );
                  if ( isstoredprocedure != null && 
!isstoredprocedure.equalsIgnoreCase( "false" ) )
                      q.setStoredProcedure( true );
                  String name =
                          attributes.getValue( "", 
SQLTransformer.MAGIC_NAME_ATTRIBUTE );
                  if ( name != null ) {
                      q.setName( name );
                  }
                  break;
              default:
                  throwIllegalStateException( "Not expecting a start query 
element" );
          }
      }
  
      protected void endQueryElement()
      throws ProcessingException, SAXException {
          switch ( current_state ) {
              case SQLTransformer.STATE_INSIDE_QUERY_ELEMENT:
                  final String value = this.endSerializedXMLRecording();
                  if ( value.length() > 0 ) {
                      this.getCurrentQuery().addQueryPart( value );
                      if (this.getLogger().isDebugEnabled()) {
                          this.getLogger().debug( "QUERY IS \"" + value + "\"" 
);
                      }
                  }
                  current_state = 
SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_ELEMENT;
                  break;
              default:
                  throwIllegalStateException( "Not expecting a stop query 
element" );
          }
      }
  
      protected void endValueElement()
      throws SAXException {
          switch ( current_state ) {
              case SQLTransformer.STATE_INSIDE_VALUE_ELEMENT:
                  final String name = (String)this.stack.pop();
                  final String value = this.endTextRecording();
                  this.getCurrentQuery().setParameter(name, value);
                  this.current_state = 
SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_ELEMENT;
                  if (this.getLogger().isDebugEnabled()) {
                      this.getLogger().debug( "SETTING VALUE ELEMENT name {" +
                                     name + "} value {" + value + "}" );
                  }
                  break;
              default:
                  throwIllegalStateException( "Not expecting an end value 
element" );
          }
      }
  
      protected void endExecuteQueryElement() throws SAXException {
          switch ( current_state ) {
              case SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_ELEMENT:
                  if ( current_query_index == 0 ) {
                      executeQuery( 0 );
                      queries.removeAllElements();
                      current_state = SQLTransformer.STATE_OUTSIDE;
                  } else {
                      current_query_index--;
                      current_state = 
SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_ELEMENT;
                  }
                  break;
              default:
                  throwIllegalStateException( "Not expecting an end execute 
query element" );
          }
      }
  
      protected void startAncestorValueElement( Attributes attributes )
      throws ProcessingException, SAXException {
          switch ( current_state ) {
              case SQLTransformer.STATE_INSIDE_QUERY_ELEMENT:
                  int level = 0;
                  try {
                      level = Integer.parseInt( attributes.getValue( NAMESPACE,
                                                                     
SQLTransformer.MAGIC_ANCESTOR_VALUE_LEVEL_ATTRIBUTE ) );
                  } catch ( Exception e ) {
                      if (this.getLogger().isDebugEnabled()) {
                          this.getLogger().debug( "SQLTransformer", e );
                      }
                      throwIllegalStateException( "Ancestor value elements must 
have a " +
                                                  
SQLTransformer.MAGIC_ANCESTOR_VALUE_LEVEL_ATTRIBUTE + " attribute" );
                  }
                  String name = attributes.getValue( NAMESPACE,
                                                     
SQLTransformer.MAGIC_ANCESTOR_VALUE_NAME_ATTRIBUTE );
                  if ( name == null ) {
                      throwIllegalStateException( "Ancestor value elements must 
have a " +
                                                  
SQLTransformer.MAGIC_ANCESTOR_VALUE_NAME_ATTRIBUTE + " attribute" );
                  }
                  AncestorValue av = new AncestorValue( level, name );
                  if (this.getLogger().isDebugEnabled()) {
                      this.getLogger().debug( "ANCESTOR VALUE " + level + " " + 
name );
                  }
  
                  final String value = this.endSerializedXMLRecording();
                  if ( value.length() > 0 ) {
                      this.getCurrentQuery().addQueryPart( value );
                      if (this.getLogger().isDebugEnabled()) {
                          this.getLogger().debug( "QUERY IS \"" + value + "\"" 
);
                      }
                  }
                  getCurrentQuery().addQueryPart( av );
                  this.startSerializedXMLRecording(format);
  
                  current_state = 
SQLTransformer.STATE_INSIDE_ANCESTOR_VALUE_ELEMENT;
                  break;
              default:
                  throwIllegalStateException( "Not expecting a start ancestor 
value element" );
          }
      }
  
      protected void endAncestorValueElement() {
          current_state = SQLTransformer.STATE_INSIDE_QUERY_ELEMENT;
      }
  
      protected void startSubstituteValueElement( Attributes attributes )
      throws ProcessingException, SAXException {
          switch ( current_state ) {
              case SQLTransformer.STATE_INSIDE_QUERY_ELEMENT:
                  String name = attributes.getValue( NAMESPACE,
                                                     
SQLTransformer.MAGIC_SUBSTITUTE_VALUE_NAME_ATTRIBUTE );
                  if ( name == null ) {
                      throwIllegalStateException( "Substitute value elements 
must have a " +
                                                  
SQLTransformer.MAGIC_SUBSTITUTE_VALUE_NAME_ATTRIBUTE + " attribute" );
                  }
                  String substitute = parameters.getParameter( name, null );
                  //escape single quote
                  substitute = replaceCharWithString( substitute, '\'', "''" );
                  if (this.getLogger().isDebugEnabled()) {
                      this.getLogger().debug( "SUBSTITUTE VALUE " + substitute 
);
                  }
                  final String value = this.endSerializedXMLRecording();
                  if ( value.length() > 0 ) {
                      this.getCurrentQuery().addQueryPart( value );
                      if (this.getLogger().isDebugEnabled()) {
                          this.getLogger().debug( "QUERY IS \"" + value + "\"" 
);
                      }
                  }
                  this.getCurrentQuery().addQueryPart( substitute );
                  this.startSerializedXMLRecording(format);
  
                  current_state = 
SQLTransformer.STATE_INSIDE_SUBSTITUTE_VALUE_ELEMENT;
                  break;
              default:
                  throwIllegalStateException( "Not expecting a start substitute 
value element" );
          }
      }
  
      protected void endSubstituteValueElement() {
          current_state = SQLTransformer.STATE_INSIDE_QUERY_ELEMENT;
      }
  
      protected void startEscapeStringElement( Attributes attributes )
      throws ProcessingException, SAXException {
          switch ( current_state ) {
              case SQLTransformer.STATE_INSIDE_QUERY_ELEMENT:
                  final String value = this.endSerializedXMLRecording();
                  if ( value.length() > 0 ) {
                      this.getCurrentQuery().addQueryPart( value );
                      if (this.getLogger().isDebugEnabled()) {
                          this.getLogger().debug( "QUERY IS \"" + value + "\"" 
);
                      }
                  }
                  this.startTextRecording();
  
                  current_state = SQLTransformer.STATE_INSIDE_ESCAPE_STRING;
                  break;
              default:
                  throwIllegalStateException( "Not expecting a start 
escape-string element" );
          }
      }
  
      protected void endEscapeStringElement()
      throws SAXException {
          switch ( current_state) {
          case SQLTransformer.STATE_INSIDE_ESCAPE_STRING:
              String value = this.endTextRecording();
              if ( value.length() > 0 ) {
                  value = replaceCharWithString( value, '\'', "''" );
                  value = replaceCharWithString( value, '\\', "\\\\" );
                  this.getCurrentQuery().addQueryPart( value );
                  if (this.getLogger().isDebugEnabled()) {
                      this.getLogger().debug( "QUERY IS \"" + value + "\"" );
                  }
              }
              this.startSerializedXMLRecording(format);
              current_state = SQLTransformer.STATE_INSIDE_QUERY_ELEMENT;
              break;
          default:
                  throwIllegalStateException( "Not expecting a end 
escape-string element" );
          }
      }
  
      protected void startInParameterElement( Attributes attributes ) {
          switch ( current_state ) {
              case SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_ELEMENT:
                  String nr = attributes.getValue( NAMESPACE,
                                                   
SQLTransformer.MAGIC_IN_PARAMETER_NR_ATTRIBUTE );
                  String value = attributes.getValue( NAMESPACE,
                                                      
SQLTransformer.MAGIC_IN_PARAMETER_VALUE_ATTRIBUTE );
                  if (this.getLogger().isDebugEnabled()) {
                      this.getLogger().debug( "IN PARAMETER NR " + nr + "; 
VALUE " + value );
                  }
                  int position = Integer.parseInt( nr );
                  getCurrentQuery().setInParameter( position, value );
                  current_state = 
SQLTransformer.STATE_INSIDE_IN_PARAMETER_ELEMENT;
                  break;
              default:
                  throwIllegalStateException( "Not expecting an in-parameter 
element" );
          }
      }
  
      protected void endInParameterElement() {
          current_state = SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_ELEMENT;
      }
  
      protected void startOutParameterElement( Attributes attributes ) {
          switch ( current_state ) {
              case SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_ELEMENT:
                  String name = attributes.getValue( NAMESPACE,
                                                     
SQLTransformer.MAGIC_OUT_PARAMETER_NAME_ATTRIBUTE );
                  String nr = attributes.getValue( NAMESPACE,
                                                   
SQLTransformer.MAGIC_OUT_PARAMETER_NR_ATTRIBUTE );
                  String type = attributes.getValue( NAMESPACE,
                                                     
SQLTransformer.MAGIC_OUT_PARAMETER_TYPE_ATTRIBUTE );
                  if (this.getLogger().isDebugEnabled()) {
                      getLogger().debug( "OUT PARAMETER NAME" + name + ";NR " + 
nr + "; TYPE " + type );
                  }
                  int position = Integer.parseInt( nr );
                  getCurrentQuery().setOutParameter( position, type, name );
                  current_state = 
SQLTransformer.STATE_INSIDE_OUT_PARAMETER_ELEMENT;
                  break;
              default:
                  throwIllegalStateException( "Not expecting an out-parameter 
element" );
          }
      }
  
      protected void endOutParameterElement() {
          current_state = SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_ELEMENT;
      }
  
      protected Query getCurrentQuery() {
          return (Query) queries.elementAt( current_query_index );
      }
  
      protected Query getQuery( int i ) {
          return (Query) queries.elementAt( i );
      }
  
      private String replaceCharWithString( String in, char c, String with ) {
          Tokenizer tok;
          StringBuffer replaced = null;
          if ( in.indexOf( c ) > -1 ) {
              tok = new Tokenizer( in, c );
              replaced = new StringBuffer();
              while ( tok.hasMoreTokens() ) {
                  replaced.append( tok.nextToken() );
                  if ( tok.hasMoreTokens() )
                      replaced.append( with );
              }
          }
          if ( replaced != null ) {
              return replaced.toString();
          } else {
              return in;
          }
      }
  
      /**
       * Qualifies an element name by giving it a prefix.
       * @param name the element name
       * @param prefix the prefix to qualify with
       * @return a namespace qualified name that is correct
       */
      protected String nsQualify( String name, String prefix ) {
          if ( name == null || "".equals( name ) ) {
              return name;
          }
          if ( prefix != null && !"".equals( prefix ) ) {
              return new StringBuffer( prefix ).append( ":" ).append( name 
).toString();
          } else {
              return name;
          }
      }
  
      /**
       * ContentHandler method
       */
      public void startPrefixMapping( String prefix, String uri )
      throws SAXException {
          if ( uri.equals( NAMESPACE ) ) {
              if (inPrefix != null) {
                  super.startPrefixMapping( inPrefix, NAMESPACE);
              }
              inPrefix = prefix;
          } else {
              super.startPrefixMapping( prefix, uri );
          }
      }
  
      /**
       * ContentHandler method
       */
      public void endPrefixMapping( String prefix )
      throws SAXException {
          if ( !prefix.equals( inPrefix ) ) {
              super.endPrefixMapping( prefix );
          }
      }
  
  
      /**
       * ContentHandler method
       */
      public void setDocumentLocator( Locator locator ) {
          if (getLogger().isDebugEnabled()) {
              getLogger().debug( "PUBLIC ID: " + locator.getPublicId() );
              getLogger().debug( "SYSTEM ID: " + locator.getSystemId() );
          }
          super.setDocumentLocator( locator );
      }
  
      /**
       * ContentHandler method
       */
      public void startTransformingElement( String uri, String name, String raw,
                                Attributes attributes )
      throws ProcessingException, SAXException {
          if (this.getLogger().isDebugEnabled()) {
              getLogger().debug( "RECEIVED START ELEMENT " + name );
          }
  
          if ( name.equals( SQLTransformer.MAGIC_EXECUTE_QUERY ) ) {
              this.startExecuteQueryElement();
          } else if ( name.equals( SQLTransformer.MAGIC_QUERY ) ) {
              this.startQueryElement( attributes );
          } else if ( name.equals( SQLTransformer.MAGIC_ANCESTOR_VALUE ) ) {
              this.startAncestorValueElement( attributes );
          } else if ( name.equals( SQLTransformer.MAGIC_SUBSTITUTE_VALUE ) ) {
              this.startSubstituteValueElement( attributes );
          } else if ( name.equals( SQLTransformer.MAGIC_IN_PARAMETER ) ) {
              this.startInParameterElement( attributes );
          } else if ( name.equals( SQLTransformer.MAGIC_OUT_PARAMETER ) ) {
              this.startOutParameterElement( attributes );
          } else if ( name.equals( SQLTransformer.MAGIC_ESCAPE_STRING ) ) {
              this.startEscapeStringElement( attributes );
          } else {
              this.startValueElement( name );
          }
      }
  
      /**
       * ContentHandler method
       */
      public void endTransformingElement( String uri, String name,
                              String raw )
      throws ProcessingException, IOException, SAXException {
          if (this.getLogger().isDebugEnabled()) {
              this.getLogger().debug( "RECEIVED END ELEMENT " + name + "(" + 
uri + ")" );
          }
  
          if ( name.equals( SQLTransformer.MAGIC_EXECUTE_QUERY ) ) {
              this.endExecuteQueryElement();
          } else if ( name.equals( SQLTransformer.MAGIC_QUERY ) ) {
              this.endQueryElement();
          } else if ( name.equals( SQLTransformer.MAGIC_ANCESTOR_VALUE ) ) {
              this.endAncestorValueElement();
          } else if ( name.equals( SQLTransformer.MAGIC_SUBSTITUTE_VALUE ) ) {
              this.endSubstituteValueElement();
          } else if ( name.equals( SQLTransformer.MAGIC_IN_PARAMETER ) ) {
              this.endInParameterElement();
          } else if ( name.equals( SQLTransformer.MAGIC_OUT_PARAMETER ) ) {
              this.endOutParameterElement();
          } else if ( name.equals( SQLTransformer.MAGIC_VALUE )
                     || current_state == 
SQLTransformer.STATE_INSIDE_VALUE_ELEMENT ) {
              this.endValueElement();
          } else  if ( name.equals( SQLTransformer.MAGIC_ESCAPE_STRING ) ) {
              this.endEscapeStringElement();
          } else {
              super.endTransformingElement( uri, name, raw );
          }
      }
  
      /**
       * Helper method for generating SAX events
       */
      private void attribute( AttributesImpl attr, String name, String value ) {
          attr.addAttribute( outUri, name, nsQualify( name, outPrefix ), 
"CDATA", value );
      }
  
      /**
       * Helper method for generating SAX events
       */
      private void start( String name, AttributesImpl attr )
      throws SAXException {
          try {
              super.startTransformingElement( outUri, name, nsQualify( name, 
outPrefix ), attr );
          } catch (IOException ioe) {
              throw new SAXException(ioe);
          } catch (ProcessingException pe) {
              throw new SAXException(pe);
          }
          attr.clear();
      }
  
      /**
       * Helper method for generating SAX events
       */
      private void end( String name ) throws SAXException {
          try {
              super.endTransformingElement( outUri, name, nsQualify( name, 
outPrefix ) );
          } catch (IOException ioe) {
              throw new SAXException(ioe);
          } catch (ProcessingException pe) {
              throw new SAXException(pe);
          }
      }
  
      /**
       * Helper method for generating SAX events
       */
      private void data( String data ) throws SAXException {
          if ( data != null ) {
              super.characters( data.toCharArray(), 0, data.length() );
          }
      }
  
      protected static String getStringValue( Object object ) {
          if ( object instanceof byte[] ) {
              return new String( (byte[]) object );
          } else if ( object instanceof char[] ) {
              return new String( (char[]) object );
          } else if ( object != null ) {
              return object.toString();
          } else {
              return "";
          }
      }
  
      public final Logger getTheLogger() {
          return getLogger();
      }
  
  
      class Query {
  
          /** Who's your daddy? **/
          protected SQLTransformer transformer;
  
          /** What index are you in daddy's queries list **/
          protected int query_index;
  
          /** SQL configuration information **/
          protected Parameters properties;
  
          /** Dummy static variables for the moment **/
          protected String rowset_name;
          protected String row_name;
          protected String nr_of_rows = "nrofrows";
          protected String name_attribute = "name";
  
          /** The connection, once opened **/
          protected Connection conn;
  
          /** And the statements **/
          protected PreparedStatement pst;
          protected CallableStatement cst;
  
          /** The results, of course **/
          protected ResultSet rs = null;
  
          /** And the results' metadata **/
          protected ResultSetMetaData md = null;
  
          /** If this query is actually an update (insert, update, delete) **/
          protected boolean isupdate = false;
  
          /** If this query is actually a stored procedure **/
          protected boolean isstoredprocedure = false;
  
          protected String name = null;
  
          /** If it is an update/etc, the return value (num rows modified) **/
          protected int rv = -1;
  
          /** The parts of the query **/
          protected Vector query_parts = new Vector();
  
          /** In parameters **/
          protected HashMap inParameters = null;
  
          /** Out parameters **/
          protected HashMap outParameters = null;
  
          /** Mapping out parameters - objectModel **/
          protected HashMap outParametersNames = null;
  
          protected Query( SQLTransformer transformer, int query_index ) {
              this.transformer = transformer;
              this.query_index = query_index;
              this.properties = new Parameters();
              this.properties.merge( transformer.parameters );
          }
  
          protected void setParameter( String name, String value ) {
              properties.setParameter( name, value );
          }
  
          protected void setUpdate( boolean flag ) {
              isupdate = flag;
          }
  
          protected void setStoredProcedure( boolean flag ) {
              isstoredprocedure = flag;
          }
  
          protected boolean isStoredProcedure() {
              return isstoredprocedure;
          }
  
          protected void setName( String name ) {
              this.name = name;
          }
  
          protected String getName() {
              return name;
          }
  
          protected void setInParameter( int pos, String val ) {
              if ( inParameters == null ) {
                  inParameters = new HashMap();
              }
              inParameters.put( new Integer( pos ), val );
          }
  
          protected void setOutParameter( int pos, String type, String name ) {
              if ( outParameters == null ) {
                  outParameters = new HashMap();
                  outParametersNames = new HashMap();
              }
              outParameters.put( new Integer( pos ), type );
              outParametersNames.put( new Integer( pos ), name );
          }
  
          private void registerInParameters( PreparedStatement pst ) throws 
SQLException {
              if ( inParameters == null )
                  return;
              Iterator itInKeys = inParameters.keySet().iterator();
              Integer counter;
              String value;
              while ( itInKeys.hasNext() ) {
                  counter = (Integer) itInKeys.next();
                  value = (String) inParameters.get( counter );
                  try {
                      pst.setObject( counter.intValue(), value );
                  } catch ( SQLException e ) {
                      transformer.getTheLogger().error( "Caught a 
SQLException", e );
                      throw e;
                  }
              }
          }
  
          private void registerOutParameters( CallableStatement cst ) throws 
SQLException {
              if ( outParameters == null )
                  return;
              Iterator itOutKeys = outParameters.keySet().iterator();
              Integer counter;
              int index;
              String type, className, fieldName;
              Class clss;
              Field fld;
              while ( itOutKeys.hasNext() ) {
                  counter = (Integer) itOutKeys.next();
                  type = (String) outParameters.get( counter );
                  index = type.lastIndexOf( "." );
                  if ( index > -1 ) {
                      className = type.substring( 0, index );
                      fieldName = type.substring( index + 1, type.length() );
                  } else {
                      transformer.getTheLogger().error( "Invalid SQLType: " + 
type, null );
                      throw new SQLException( "Invalid SQLType: " + type);
                  }
                  try {
                      clss = Class.forName( className );
                      fld = clss.getField( fieldName );
                      cst.registerOutParameter( counter.intValue(), fld.getInt( 
fieldName ) );
                  } catch ( Exception e ) {
                      //lots of different exceptions to catch
                      transformer.getTheLogger().error( "Invalid SQLType: " +
                                                        className + "." + 
fieldName, e );
                  }
              }
          }
  
          /** Get a Connection. Made this a separate method to separate the 
logic from the actual execution. */
          protected Connection getConnection() throws SQLException {
              Connection result = null;
  
              try {
                  final String connection = properties.getParameter( 
SQLTransformer.MAGIC_CONNECTION, null );
                  if ( connection != null ) {
                      if (this.transformer.dbSelector == null) {
                          transformer.getTheLogger().error( "No DBSelector 
found, could not use connection: " + connection);
                      } else {
                          DataSourceComponent datasource = null;
  
                          try {
                              datasource = (DataSourceComponent) 
this.transformer.dbSelector.select( connection );
                              for ( int i = 0; i < transformer.connectAttempts 
&& result == null; i++) {
                                  try {
                                      result = datasource.getConnection();
                                  } catch ( Exception e ) {
                                      final long waittime = 
transformer.connectWaittime;
                                      transformer.getTheLogger().debug(
                                              "SQLTransformer$Query: could not 
acquire a Connection -- waiting "
                                              + waittime + " ms to try again." 
);
                                      try {
                                          Thread.sleep( waittime );
                                      } catch ( InterruptedException ie ) {
                                      }
                                  }
                              }
                          } catch ( ComponentException cme ) {
                               transformer.getTheLogger().error( "Could not use 
connection: " + connection, cme );
                          } finally {
                              if ( datasource != null ) 
this.transformer.dbSelector.release( datasource );
                          }
  
                          if (result == null) {
                              throw new SQLException("Failed to obtain 
connection. Made "
                                      + transformer.connectAttempts + " 
attempts with "
                                      + transformer.connectWaittime + "ms 
interval");
                          }
                      }
                  } else {
                      final String dburl = properties.getParameter( 
SQLTransformer.MAGIC_DBURL, null );
                      final String username = properties.getParameter( 
SQLTransformer.MAGIC_USERNAME, null );
                      final String password = properties.getParameter( 
SQLTransformer.MAGIC_PASSWORD, null );
  
                      if ( username == null || password == null ) {
                          result = DriverManager.getConnection( dburl );
                      } else {
                          result = DriverManager.getConnection( dburl, username,
                                                                password );
                      }
                  }
              } catch ( SQLException e ) {
                  transformer.getTheLogger().error( "Caught a SQLException", e 
);
                  throw e;
              }
  
              return result;
          }
  
          protected void execute() throws SQLException {
              this.rowset_name = properties.getParameter( 
SQLTransformer.MAGIC_DOC_ELEMENT, "rowset" );
              this.row_name = properties.getParameter( 
SQLTransformer.MAGIC_ROW_ELEMENT, "row" );
  
              Enumeration enum = query_parts.elements();
              StringBuffer sb = new StringBuffer();
              while ( enum.hasMoreElements() ) {
                  Object object = enum.nextElement();
                  if ( object instanceof String ) {
                      sb.append( (String) object );
                  } else if ( object instanceof AncestorValue ) {
                      /** Do a lookup into the ancestors' result's values **/
                      AncestorValue av = (AncestorValue) object;
                      Query query = transformer.getQuery( query_index - 
av.level );
                      sb.append( query.getColumnValue( av.name ) );
                  }
              }
              String query = sb.toString().trim();
              // Test, if this is an update (by comparing with select)
              if ( !isstoredprocedure && !isupdate) {
                  if (query.length() > 6 && 
!query.substring(0,6).equalsIgnoreCase("SELECT")) {
                      isupdate = true;
                  }
              }
              if (transformer.getTheLogger().isDebugEnabled()) {
                  transformer.getTheLogger().debug( "EXECUTING " + query );
              }
  
              conn = getConnection();
  
              try {
                  if ( !isstoredprocedure ) {
                      if ( oldDriver ) {
                          pst = conn.prepareStatement( query );
                      } else {
                          pst = conn.prepareStatement( query,
                                                       
ResultSet.TYPE_SCROLL_INSENSITIVE,
                                                       
ResultSet.CONCUR_READ_ONLY );
                      }
                  } else {
                      if ( oldDriver ) {
                          cst = conn.prepareCall( query );
                      } else {
                          cst = conn.prepareCall( query,
                                                  
ResultSet.TYPE_SCROLL_INSENSITIVE,
                                                  ResultSet.CONCUR_READ_ONLY );
                      }
                      registerOutParameters( cst );
                      pst = cst;
                  }
  
                  registerInParameters( pst );
                  boolean result = pst.execute();
                  if ( result ) {
                      rs = pst.getResultSet();
                      md = rs.getMetaData();
                  } else {
                      rv = pst.getUpdateCount();
                  }
              } catch ( SQLException e ) {
                  transformer.getTheLogger().error( "Caught a SQLException", e 
);
                  throw e;
              } finally {
                  conn.close();
                  conn = null;        // To make sure we don't use this 
connection again.
              }
          }
  
          protected int getNrOfRows() throws SQLException {
              int nr = 0;
              if ( rs != null ) {
                  if ( oldDriver ) {
                      nr = -1;
                  } else {
                      try {
                          rs.last();
                          nr = rs.getRow();
                          rs.beforeFirst();
                      } catch ( NullPointerException e ) {
                          // A NullPointerException here crashes a whole lot of 
C2 -- catching it so it won't do any harm for now, but seems like it should be 
solved seriously
                          getTheLogger().error( "NPE while getting the nr of 
rows", e );
                      }
                  }
              } else {
                  if ( outParameters != null ) {
                      nr = outParameters.size();
                  }
              }
              return nr;
          }
  
          protected String getColumnValue( int i ) throws SQLException {
              String retval =  transformer.getStringValue( rs.getObject( i ) );
              if (rs.getMetaData().getColumnType(i) == 8)
              retval = transformer.getStringValue( rs.getBigDecimal( i ) );
              return retval;
          }
  
          //fix not applied here because there is no metadata from Name -> 
number and coltype
          //for a given "name" versus number.  That being said this shouldn't 
be an issue
          //as this function is only called for ancestor lookups.
          protected String getColumnValue( String name ) throws SQLException {
              String retval =  transformer.getStringValue( rs.getObject( name ) 
);
  //          if (rs.getMetaData().getColumnType( name ) == 8)
  //            retval = transformer.getStringValue( rs.getBigDecimal( name ) );
              return retval;
          }
  
          protected boolean next() throws SQLException {
              // if rv is not -1, then an SQL insert, update, etc, has
              // happened (see JDBC docs - return codes for executeUpdate)
              if ( rv != -1 )
                  return false;
              try {
                  if ( rs == null || !rs.next() ) {
                      //close();
                      return false;
                  }
              } catch ( NullPointerException e ) {
                  getTheLogger().debug( "NullPointerException, returning 
false.", e );
                  return false;
              }
              return true;
          }
  
          protected void close() throws SQLException {
              try {
                  if ( rs != null )
                      try {
                          //getTheLogger().debug("Trying to close resultset 
"+rs.toString());
                          rs.close();
                          rs = null;      // This prevents us from using the 
resultset again.
                          //250getTheLogger().debug("Really closed the 
resultset now.");
                      } catch ( NullPointerException e ) {
                          getTheLogger().debug( "NullPointer while closing the 
resultset.", e );
                      }
                  if ( pst != null )
                      pst.close();
                  pst = null;        // Prevent using pst again.
                  if ( cst != null )
                      cst.close();
                  cst = null;        // Prevent using cst again.
              } finally {
                  if ( conn != null )
                      conn.close();
                  conn = null;
              }
          }
  
          protected void addQueryPart( Object object ) {
              query_parts.addElement( object );
          }
  
          protected void serializeData(ComponentManager manager,
                                       String           value)
          throws SQLException, SAXException {
              if (value != null) {
                  value = value.trim();
                  // Could this be XML ?
                  if (value.length() > 0 && value.charAt(0) == '<') {
                      try {
                          if (transformer.parser != null) {
                              transformer.parser = 
(Parser)manager.lookup(Parser.ROLE);
                          }
                          if (transformer.compiler != null) {
                              compiler = 
(XMLSerializer)manager.lookup(XMLSerializer.ROLE);
                          }
                          if (transformer.interpreter != null) {
                              interpreter = 
(XMLDeserializer)manager.lookup(XMLDeserializer.ROLE);
                          }
                          parser.parse(new InputSource(new 
StringReader("<root>"+value+"</root>")), compiler);
  
                          IncludeXMLConsumer filter = new 
IncludeXMLConsumer(transformer, transformer);
                          filter.setIgnoreRootElement(true);
  
                          interpreter.setConsumer(filter);
  
                          interpreter.deserialize(compiler.getSAXFragment());
                      } catch (Exception local) {
                          // if an exception occured the data was not xml
                          transformer.data(value);
                      }
                  } else {
                      transformer.data(value);
                  }
              }
          }
  
          protected void serializeRow(ComponentManager manager)
          throws SQLException, SAXException {
              AttributesImpl attr = new AttributesImpl();
              if ( !isupdate && !isstoredprocedure ) {
                  for ( int i = 1; i <= md.getColumnCount(); i++ ) {
                      transformer.start( md.getColumnName( i ).toLowerCase(), 
attr );
                      this.serializeData(manager, getColumnValue( i ) );
                      transformer.end( md.getColumnName( i ).toLowerCase() );
                  }
              } else if ( isupdate && !isstoredprocedure ) {
                  transformer.start( "returncode", attr );
                  this.serializeData(manager, String.valueOf( rv ) );
                  transformer.end( "returncode" );
                  rv = -1; // we only want the return code shown once.
              }
          }
  
          protected void serializeStoredProcedure(ComponentManager manager)
          throws SQLException, SAXException {
              if ( outParametersNames == null || cst == null )
                  return;
              //make sure output follows order as parameter order in stored 
procedure
              Iterator itOutKeys = ( new TreeMap( outParameters ) 
).keySet().iterator();
              Integer counter;
              AttributesImpl attr = new AttributesImpl();
              try {
                  while ( itOutKeys.hasNext() ) {
                      counter = (Integer) itOutKeys.next();
                      try {
                          if ( cst == null ) getTheLogger().debug( 
"SQLTransformer: cst is null" );
                          if ( counter == null ) getTheLogger().debug( " 
SQLTransformer: counter is null" );
                          Object obj = cst.getObject( counter.intValue() );
                          if ( !( obj instanceof ResultSet ) ) {
                              transformer.start( (String) 
outParametersNames.get( counter ), attr );
                              this.serializeData(manager, 
transformer.getStringValue( obj ) );
                              transformer.end( (String) outParametersNames.get( 
counter ) );
                          } else {
                              ResultSet rs = (ResultSet) obj;
                              try {
                                  transformer.start( (String) 
outParametersNames.get( counter ), attr );
                                  ResultSetMetaData md = rs.getMetaData();
                                  while ( rs.next() ) {
                                      transformer.start( this.row_name, attr );
                                      for ( int i = 1; i <= 
md.getColumnCount(); i++ ) {
                                          transformer.start( md.getColumnName( 
i ).toLowerCase(), attr );
                                          if ( md.getColumnType( i ) == 8 ) {  
//prevent nasty exponent notation
                                              this.serializeData(manager, 
transformer.getStringValue( rs.getBigDecimal( i ) ));
                                          } else {
                                              this.serializeData(manager, 
transformer.getStringValue( rs.getObject( i ) ));
                                          }
                                          transformer.end( md.getColumnName( i 
).toLowerCase() );
                                      }
                                      transformer.end( this.row_name );
                                  }
                              } finally {
                                  rs.close();
                                  rs = null;
                              }
                              transformer.end( (String) outParametersNames.get( 
counter ) );
                          }
                      } catch ( SQLException e ) {
                          transformer.getTheLogger().error( "Caught a 
SQLException", e );
                          throw e;
                      }
                  }
              } finally {
                  //close();
              }
          }
      }
  
      private class AncestorValue {
          protected int level;
          protected String name;
  
          protected AncestorValue( int level, String name ) {
              this.level = level;
              this.name = name;
          }
      }
  
  }
  
  
  
  1.1                  
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/reading/DatabaseReader.java
  
  Index: DatabaseReader.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
      [EMAIL PROTECTED]
  
   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  <[EMAIL PROTECTED]>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  package org.apache.cocoon.reading;
  
  import org.apache.avalon.excalibur.datasource.DataSourceComponent;
  import org.apache.avalon.framework.activity.Disposable;
  import org.apache.avalon.framework.component.*;
  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.parameters.Parameters;
  import org.apache.cocoon.ProcessingException;
  import org.apache.cocoon.ResourceNotFoundException;
  import org.apache.cocoon.caching.CacheableProcessingComponent;
  import org.apache.cocoon.environment.ObjectModelHelper;
  import org.apache.cocoon.environment.Request;
  import org.apache.cocoon.environment.Response;
  import org.apache.cocoon.environment.SourceResolver;
  import org.apache.cocoon.util.HashUtil;
  import org.apache.excalibur.source.SourceValidity;
  import org.apache.excalibur.source.impl.validity.NOPValidity;
  import org.apache.excalibur.source.impl.validity.TimeStampValidity;
  import org.xml.sax.SAXException;
  
  import java.io.BufferedInputStream;
  import java.io.IOException;
  import java.io.InputStream;
  import java.sql.*;
  import java.util.Date;
  import java.util.Map;
  
  /**
   * This Reader pulls a resource from a database.  It is configured with
   * the Connection to use, parameters specify the table and column
   * to pull the image from, and source specifies the source key information.
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Berin Loritsch</a>
   * @version CVS $Id: DatabaseReader.java,v 1.1 2002/10/18 14:04:26 haul Exp $
   */
  public class DatabaseReader
     extends ComposerReader
     implements Configurable, Disposable, CacheableProcessingComponent {
      private ComponentSelector dbselector;
      private String dsn;
      private long lastModified = System.currentTimeMillis();
      private Blob resource = null;
      private Connection con = null;
      private DataSourceComponent datasource = null;
      private boolean doCommit = false;
      private boolean defaultCache = true;
  
      /**
       * Compose the object so that we get the <code>Component</code>s we need 
from
       * the <code>ComponentManager</code>.
       */
      public void compose(final ComponentManager manager) throws 
ComponentException {
          super.compose(manager);
          this.dbselector = (ComponentSelector) 
manager.lookup(DataSourceComponent.ROLE + "Selector");
      }
  
      /**
       * Configure the <code>Reader</code> so that we can use the same database
       * for all instances.
       */
      public void configure(Configuration conf) throws ConfigurationException {
          this.dsn = conf.getChild("use-connection").getValue();
          this.defaultCache = 
conf.getChild("invalidate").getValue("never").equals("always");
      }
  
      /**
       * Set the <code>SourceResolver</code> the object model <code>Map</code>,
       * the source and sitemap <code>Parameters</code> used to process the 
request.
       */
      public void setup(SourceResolver resolver, Map objectModel, String src, 
Parameters par)
          throws ProcessingException, SAXException, IOException {
          super.setup(resolver, objectModel, src, par);
  
          try {
              this.datasource = (DataSourceComponent) dbselector.select(dsn);
              this.con = datasource.getConnection();
  
              if (this.con.getAutoCommit()) {
                  this.con.setAutoCommit(false);
              }
  
              PreparedStatement statement = con.prepareStatement(getQuery());
              statement.setString(1, this.source);
              ResultSet set = statement.executeQuery();
              if (!set.next()) throw new ResourceNotFoundException("There is no 
resource with that key");
  
              Response response = ObjectModelHelper.getResponse(objectModel);
              Request request = ObjectModelHelper.getRequest(objectModel);
  
              if (this.modifiedSince(set, request, response)) {
                  this.resource = set.getBlob(1);
  
                  if (this.resource == null) {
                      throw new ResourceNotFoundException("There is no resource 
with that key");
                  }
              }
  
              this.doCommit = true;
          } catch (Exception e) {
              this.doCommit = false;
  
              throw new ResourceNotFoundException("DatabaseReader error:", e);
          }
      }
  
      /**
       * Generates the resource we need to retrieve verbatim from the
       * database.  Granted, this can be used for any resource from a
       * database, so we may want to get rid of the bias toward images.
       * This reader requires a number of parameters:
       *
       * <pre>
       *   &lt;parameter name="table" value="database_table_name"/&gt;
       *   &lt;parameter name="image" value="database_resource_column_name"/&gt;
       *   &lt;parameter name="key" value="database_lookup_key_column_name"/&gt;
       * </pre>
       *
       * Please note that if any of those parameters are missing, this
       * <code>Reader</code> cannot function.  There are a number of other
       * parameters that allow you to provide hints for the reader to
       * optimize resource use:
       *
       * <pre>
       *   &lt;parameter name="last-modified" 
value="database_timestamp_column_name"/&gt;
       *   &lt;parameter name="content-type" value="content_mime_type"/&gt;
       *   &lt;parameter name="expires" 
value="number_of_millis_before_refresh"/&gt;
       *   &lt;parameter name="where" value="alternate_key = 'foo'"/&gt;
       *   &lt;parameter name="order-by" value="alternate_key DESC"/&gt;
       * </pre>
       *
       * Lastly, the <code>key</code> value is derived from the value of
       * the <code>source</code> string.
       */
      public void generate() throws ProcessingException, SAXException, 
IOException {
          try {
              Response response = ObjectModelHelper.getResponse(objectModel);
              this.serialize(response);
          } catch (IOException ioe) {
              getLogger().warn("Assuming client reset stream");
  
              this.doCommit = false;
          } catch (Exception e) {
              this.doCommit = false;
  
              throw new ResourceNotFoundException("DatabaseReader error:", e);
          }
      }
  
      /**
       * This method builds the query string used for accessing the database.
       * If the required parameters do not exist, then we cannot build a
       * correct query.
       */
      public String getQuery() throws Exception {
          String table = this.parameters.getParameter("table", null);
          String column = this.parameters.getParameter("image", null);
          String key = this.parameters.getParameter("key", null);
          String where = this.parameters.getParameter("where", null);
          String orderBy = this.parameters.getParameter("order-by", null);
  
          if (table == null || column == null || key==null) {
              throw new ProcessingException("We are missing a required 
parameter.  Please include 'table', 'image', and 'key'");
          }
  
          String date = this.parameters.getParameter("last-modified", null);
          StringBuffer query = new StringBuffer("SELECT ");
  
          query.append(column);
  
          if (date != null) {
              query.append(", ").append(date);
          }
  
          if (null != orderBy) {
              query.append(", ");
  
              if (orderBy.endsWith(" DESC")) {
                  query.append(orderBy.substring(0, orderBy.length() - 5));
              } else {
                  query.append(orderBy);
              }
          }
  
          query.append(" FROM ").append(table);
          query.append(" WHERE ").append(key).append(" = ?");
  
          if (null != where) {
              query.append(" AND ").append(where);
          }
  
          if (null != orderBy) {
              query.append(" ORDER BY ").append(orderBy);
          }
  
          return query.toString();
      }
  
      /**
       * Tests whether a resource has been modified or not.  As Blobs and
       * database columns usually do not have intrinsic dates on them (at
       * least easily accessible), we have to have a database column that
       * holds a date for the resource.  Please note, that the database
       * column <strong>must</strong> be a <code>Timestamp</code> column.
       *
       * In the absence of such a column this method <em>always</em>
       * returns <code>true</code>.  This is because databases are much
       * more prone to change than filesystems, and don't have intrinsic
       * timestamps on column updates.
       */
      public boolean modifiedSince(ResultSet set, Request request, Response 
response)
      throws SQLException {
          String lastModified = this.parameters.getParameter("last-modified", 
null);
  
          if (lastModified != null) {
              Timestamp modified = set.getTimestamp(lastModified, null);
              if (null != modified) {
                  this.lastModified = modified.getTime();
              } else {
                  // assume it has never been modified
              }
  
              response.setDateHeader("Last-Modified", this.lastModified);
  
              return this.lastModified > 
request.getDateHeader("if-modified-since");
          }
  
          // if we have nothing to compare to, then we must assume it
          // has been modified
          return true;
      }
  
      /**
       * This method actually performs the serialization.
       */
      public void serialize(Response response)
      throws IOException, SQLException {
          if (this.resource == null) {
              throw new SQLException("The Blob is empty!");
          }
  
          InputStream is = new 
BufferedInputStream(this.resource.getBinaryStream());
  
          long expires = parameters.getParameterAsInteger("expires", -1);
  
          if (expires > 0) {
              response.setDateHeader("Expires", System.currentTimeMillis() + 
expires);
          }
  
          response.setHeader("Accept-Ranges", "bytes");
  
          byte[] buffer = new byte[8192];
          int length = -1;
  
          while ((length = is.read(buffer)) > -1) {
              out.write(buffer, 0, length);
          }
          is.close();
          out.flush();
      }
  
      /**
       * Generate the unique key.
       * This key must be unique inside the space of this component.
       *
       * @return The generated key hashes the src
       */
      public java.io.Serializable generateKey() {
          return this.source;
      }
  
      /**
       * Generate the validity object.
       *
       * @return The generated validity object or <code>null</code> if the
       *         component is currently not cacheable.
       */
      public SourceValidity generateValidity() {
          if (this.lastModified > 0) {
              return new TimeStampValidity(this.lastModified);
          } else {
              if (this.defaultCache) {
                  return NOPValidity.SHARED_INSTANCE;
              } else {
                  return null;
              }
          }
      }
  
      public void recycle() {
          super.recycle();
          this.resource = null;
          this.lastModified = 0;
  
          if (this.con != null) {
              try {
                  if (this.doCommit) {
                      this.con.commit();
                  } else {
                      this.con.rollback();
                  }
              } catch (SQLException se) {
                  getLogger().warn("Could not commit or rollback connection", 
se);
              }
  
              try {
                  this.con.close();
              } catch (SQLException se) {
                  getLogger().warn("Could not close connection", se);
              }
  
              this.con = null;
          }
  
          if (this.datasource != null) {
              this.dbselector.release(this.datasource);
              this.datasource = null;
          }
      }
  
      /**
       * dispose()
       */
      public void dispose()
      {
          this.manager.release(this.dbselector);
      }
  
      public String getMimeType() {
          return this.parameters.getParameter("content-type", 
super.getMimeType());
      }
  
  }
  
  
  
  1.1                  
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/components/modules/input/CollectionMetaModule.java
  
  Index: CollectionMetaModule.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
      [EMAIL PROTECTED]
  
   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  <[EMAIL PROTECTED]>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  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;
  
  import org.apache.cocoon.components.modules.input.InputModule;
  import org.apache.cocoon.util.JDBCTypeConversions;
  
  import org.apache.cocoon.matching.AbstractWildcardMatcher;
  
  import java.util.ArrayList;
  import java.util.Map;
  import java.util.Enumeration;
  import java.util.SortedSet;
  import java.util.TreeSet;
  
  /**
   * Constructs an array of values suitable for a JDBC collection type
   * from parameters obtained from another input module. Application is
   * not limited to JDBC collections but can be used wherever similar
   * named attributes shall be collected to an array of a given
   * type. Currently, long, int, and string are known, more to come.
   *
   * <p><b>Global and local configuration</b></p>
   * <table border="1">
   * <tr><td><code>input-module</code></td><td>Name of the input module used to 
obtain the value and its configuration</td></tr>
   * <tr><td><code>member</code></td>      <td>Collection member <table
   *                                           
<tr><td>Attribute</td><td></td></tr>
   *                                           <tr><td>name</td><td>Parameter 
name, "*" may distinguish multiple collections</td></tr>
   *                                           <tr><td>type</td><td>JDBC type 
name of members</td></tr>
   *                                           </table>                       
</td></tr>
   * </table>
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Christian Haul</a>
   * @version CVS $Id: CollectionMetaModule.java,v 1.1 2002/10/18 14:04:26 haul 
Exp $
   */
  public class CollectionMetaModule extends AbstractLogEnabled
      implements InputModule, Configurable, Initializable, Composable, 
Disposable {
  
      /** The component manager instance */
      protected ComponentManager manager;
  
      protected Configuration memberConf = null;
  
      private String defaultInput = "request-param"; // default to request 
parameters
      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;
  
  
  
      /**
       * 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.memberConf = config.getChild("member");
          this.inputConf = config.getChild("input-module");
          this.defaultInput = 
this.inputConf.getAttribute("name",this.defaultInput);
      }
  
  
  
      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 (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"));
              }
          } 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 getAttribute( 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. FAILING");
              return null;
          }
  
          // obtain correct configuration objects
          // default vs dynamic
          Configuration mConf = this.memberConf;
          Configuration inputConfig = null;
          String inputName=null;
          if (modeConf!=null) {
              mConf       = modeConf.getChild("member");
              inputName   = 
modeConf.getChild("input-module").getAttribute("name",null);
              if (inputName != null) {
                  inputConfig = modeConf.getChild("input-module");
              }
          }
  
          // read necessary parameters
          // name is used only if parameter name contains '*'
          // in that case it replaces '*' otherwise it is
          // ignored
          String jType = mConf.getAttribute("type","string");
          SortedSet matchset = new TreeSet();
          String pName = mConf.getAttribute("name");
          int index = pName.indexOf("*");
          if (index>-1) {
              String prefix = (index > 0 ? pName.substring(0,index) : null);
              String suffix = (index < (pName.length() -1) ? 
pName.substring(index+1,pName.length()) : null);
              pName = prefix+name+suffix;
          }
  
          getLogger().debug("jType "+jType);
  
          // done reading configuration
          // setup modules and read values
          Object result = null;
          try {
              Object[] values = 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(pName,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 (this.defaultInput != null 
                          && iputSelector != null 
                          && iputSelector.hasComponent(inputName)) {
                          
                          iput = (InputModule) iputSelector.select(inputName);
                      }
                      if (iput != null) {
                          values = iput.getAttributeValues(pName, inputConfig, 
objectModel);
                      }           
                  } catch (Exception e) {
                      if (getLogger().isWarnEnabled()) 
                          getLogger().warn("A problem occurred acquiring a 
value from '" 
                                           + inputName + "' for '"+pName+"': " 
+ 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) {
                  
                  Object[] objects = new Object[values.length];
                      
                  // FIXME: should put this into helper class
                  for (int i = 0; i<values.length; i++) {
                      Object value = values[i];
                      objects[i] = JDBCTypeConversions.convert(value, jType);
                  }
                  return objects;
              }
          } catch (Exception e) {
              if (getLogger().isWarnEnabled()) 
                  getLogger().warn("A problem occurred acquiring a value from 
'" + inputName 
                                   + "' for '"+pName+"': " + e.getMessage());
          }
          return null;        
      }
  
  
  
  
  
      public Enumeration 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
  
          Configuration mConf = this.memberConf;
          Configuration inputConfig = null;
          String inputName=null;
          if (modeConf!=null) {
              mConf       = modeConf.getChild("member");
              inputName   = 
modeConf.getChild("input-module").getAttribute("name",null);
              if (inputName != null) {
                  inputConfig = modeConf.getChild("input-module");
              }
          }
  
          // done reading configuration
          // setup modules and read attribute names
          Object result = null;
          try {
              Enumeration names = 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
                  names = input.getAttributeNames(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 (this.defaultInput != null 
                          && iputSelector != null 
                          && iputSelector.hasComponent(inputName)) {
                          
                          iput = (InputModule) iputSelector.select(inputName);
                      }
                      if (iput != null) {
                          names = iput.getAttributeNames(inputConfig, 
objectModel);
                      }           
                  } catch (Exception e) {
                      if (getLogger().isWarnEnabled()) 
                          getLogger().warn("A problem occurred acquiring a 
names from '" + inputName + "': " + e.getMessage());
                  } finally {
                      // release components
                      if (iputSelector != null) {
                          if (iput != null)
                              iputSelector.release(iput);
                          this.manager.release(iputSelector);
                      }
                  }
  
              }
  
              // done reading names
              // find attribute names matching configuration
              // and return an enumeration
  
              if (names != null) {
                  SortedSet matchset = new TreeSet();
                  String pName = mConf.getAttribute("name");
                  int index = pName.indexOf("*");
  
                  if (index>-1) {
                      // parameter name contains '*'
                      // find all strings that match this '*'
                      // return them in an enumeration
  
                      String prefix = (index > 0 ? pName.substring(0,index) : 
null);
                      String suffix = (index < (pName.length() -1) ? 
pName.substring(index+1,pName.length()) : null);
  
                      while (names.hasMoreElements()) {
                          String name = (String)names.nextElement();
                          if (name.startsWith(prefix) && name.endsWith(suffix)) 
{
                              String wildcard = name.substring(prefix.length());
                              wildcard = 
wildcard.substring(0,wildcard.length()-suffix.length());
                              matchset.add(wildcard);
                          }
                      }
                  } else {
                      // parameter name without wildcard
                      // check that name is among available names
                      // and return it in that case
                      boolean done=false;
                      while (!done && names.hasMoreElements()) {
                          String name = (String)names.nextElement();
                          if (name.equals(pName)) {
                              matchset.add(pName);
                              done = true;
                          }
                      }
                  }
                  return new EnumerationHelper(matchset.iterator());
              } else {
                  return null;
              }
  
          } catch (Exception e) {
              if (getLogger().isWarnEnabled()) 
                  getLogger().warn("A problem occurred acquiring names from '" 
+ inputName + "': " + e.getMessage());
          }
          return null;        
      }
  
  
  
  
      public Object[] getAttributeValues( String name, Configuration modeConf, 
Map objectModel ) 
          throws ConfigurationException {
  
          Enumeration names = this.getAttributeNames( modeConf, objectModel );
          ArrayList values = new ArrayList();
          while (names.hasMoreElements()) {
              values.add(this.getAttribute((String) 
names.nextElement(),modeConf,objectModel));
          }
  
          return values.toArray();
  
      }
  
  }
  
  
  
  1.1                  
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/components/modules/database/AbstractAutoIncrementModule.java
  
  Index: AbstractAutoIncrementModule.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
      [EMAIL PROTECTED]
  
   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  <[EMAIL PROTECTED]>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  
  package org.apache.cocoon.components.modules.database;
  
  import org.apache.avalon.framework.activity.Disposable;
  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.logger.AbstractLogEnabled;
  
  import org.apache.cocoon.util.HashMap;
  
  /**
   * AbstractDatabaseModule gives you the infrastructure for easily
   * deploying more AutoIncrementModules.  In order to get at the Logger, use
   * getLogger().
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Christian Haul</a>
   * @version CVS $Id: AbstractAutoIncrementModule.java,v 1.1 2002/10/18 
14:04:26 haul Exp $
   */
  public abstract class AbstractAutoIncrementModule extends AbstractLogEnabled
      implements AutoIncrementModule, Configurable, Disposable {
  
      /**
       * Stores (global) configuration parameters as <code>key</code> /
       * <code>value</code> pairs.
       */
      protected HashMap settings = null;
  
      /**
       * Configures the database access module.
       *
       * Takes all elements nested in component declaration and stores
       * them as key-value pairs in <code>settings</code>. Nested
       * configuration option are not catered for. This way global
       * configuration options can be used.
       *
       * For nested configurations override this function.
       * */
      public void configure(Configuration conf) throws ConfigurationException {
  
          if (conf != null) {
              String key = null;
              String val = null;
              Configuration[] parameters = conf.getChildren();
              this.settings = new HashMap(parameters.length);
              for ( int i = 0; i < parameters.length; i++) {
                  key = parameters[i].getName();
                  val = parameters[i].getValue();
                  if ( key != null )
                      this.settings.put(key, val);
              }
          }
      }
  
      /**
       *  dispose
       */
      public void dispose() {
          // Purposely empty so that we don't need to implement it in every
          // class.
      }
  }
  
  
  
  1.1                  
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/components/modules/database/AutoIncrementModule.java
  
  Index: AutoIncrementModule.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
      [EMAIL PROTECTED]
  
   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  <[EMAIL PROTECTED]>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  
  package org.apache.cocoon.components.modules.database;
  
  import java.sql.Connection;
  import java.sql.Statement;
  import java.sql.SQLException;
  import java.util.Map;
  import org.apache.avalon.framework.component.Component;
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.configuration.ConfigurationException;
  
  /**
   * Abstraction layer to encapsulate different DBMS behaviour for key
   * attribute columns.
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Christian Haul</a>
   * @version CVS $Id: AutoIncrementModule.java,v 1.1 2002/10/18 14:04:26 haul 
Exp $
   * */
  public interface AutoIncrementModule extends Component {
  
      String ROLE = AutoIncrementModule.class.getName();
  
  
      /**
       * Return key attribute value of last inserted row.
       *
       * @param name a String that specifies what the caller thinks
       * would identify a set of parameters. This is mainly a fallback
       * if no modeConf is present.
  
       * @param tableConf Table's configuration from resource description.
       * @param columnConf column's configuration from resource description.
       * @param mdoeConf this mode's configuration from resource description.
       * @param conn Connection
       * @param stmt Statement that was executed to insert the last row.
       * @param request The request object
       * @return value representing the last key value value.
       * */
      Object getPostValue( Configuration tableConf, Configuration columnConf, 
Configuration modeConf,
                           Connection conn, Statement stmt, Map objectModel ) 
throws SQLException, ConfigurationException;
  
  
      /**
       * Boolean whether the key attribute column needs to be included
       * in the insert query.
       *
       * @return true if the column is needed, false if the column
       * should be skipped.
       * */
      boolean includeInQuery( );
  
  
      /**
       * Boolean whether the key attribute needs to be included in the
       * insert query as an attribute value (no subquery).
       *
       * @return true if a value is needed, false if a subquery
       * expression is used or the column is skipped altogether.
       * */
      boolean includeAsValue( );
  
  
      /**
       * Provide the value for the key attribute column.
       *
       * If a value for the key value column is needed (i.e. the column
       * is not skipped), this value is computed here.
       *
       * @param tableConf Table's configuration from resource description.
       * @param columnConf column's configuration from resource description.
       * @param mdoeConf this mode's configuration from resource description.
       * @param conn Connection
       * @param request The request object
       * @param idx In case of multiple rows to be inserted, index to the 
desired row
       * @return exact value for key attribute column
       * */
      Object getPreValue( Configuration tableConf, Configuration columnConf, 
Configuration modeConf,
                          Connection conn, Map objectModel ) throws 
SQLException, ConfigurationException;
  
  
      /**
       * Provide subquery string for the key attribute column.
       *
       * If a value for the autoincrement column is needed (i.e. the
       * column is not skipped), and the value can be determined through
       * a nested subquery, this function provides the subquery as a
       * string.
       *
       * @return subquery string for autoincrement column.
       */
      String getSubquery( Configuration tableConf, Configuration columnConf, 
Configuration modeConf ) throws ConfigurationException;
  
  }
  
  
  
  1.1                  
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/components/modules/database/HsqlIdentityAutoIncrementModule.java
  
  Index: HsqlIdentityAutoIncrementModule.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
      [EMAIL PROTECTED]
  
   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  <[EMAIL PROTECTED]>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  
  package org.apache.cocoon.components.modules.database;
  
  import java.lang.Integer;
  import java.util.SortedSet;
  import java.util.Map;
  import java.sql.CallableStatement;
  import java.sql.PreparedStatement;
  import java.sql.Connection;
  import java.sql.ResultSet;
  import java.sql.Statement;
  import java.sql.Types;
  import java.sql.SQLException;
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.configuration.ConfigurationException;
  import org.apache.avalon.framework.thread.ThreadSafe;
  
  /**
   * Abstraction layer to encapsulate different DBMS behaviour for 
autoincrement columns.
   *
   * Here: [EMAIL PROTECTED] <a 
href="http://hsqldb.sourceforge.net";>HSQLDB</a>} 1.6 IDENTITY columns
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Christian Haul</a>
   * @version CVS $Id: HsqlIdentityAutoIncrementModule.java,v 1.1 2002/10/18 
14:04:26 haul Exp $
   */
  public class HsqlIdentityAutoIncrementModule implements AutoIncrementModule, 
ThreadSafe {
  
      public Object getPostValue( Configuration tableConf, Configuration 
columnConf, Configuration modeConf,
                                  Connection conn, Statement stmt, Map 
objectModel )  throws SQLException, ConfigurationException {
  
          Integer id = null;
          /*
            // if hsqldb did support callable statements ...
  
            CallableStatement callStmt = conn.prepareCall("? = {CALL 
IDENTITY()}");
            callStmt.registerOutParameter(1, Types.INTEGER);
            ResultSet resultSet = callStmt.executeQuery();
          */
  
          PreparedStatement pstmt = conn.prepareStatement("CALL IDENTITY()");
          ResultSet resultSet = pstmt.executeQuery();
          while ( resultSet.next() ) {
              id = new Integer(resultSet.getInt(1));
          }
          resultSet.close();
  
          return id;
      }
  
  
      public boolean includeInQuery() { return false; }
  
  
      public boolean includeAsValue() { return false; }
  
  
      public Object getPreValue( Configuration tableConf, Configuration 
columnConf, Configuration modeConf,
                                 Connection conn, Map objectModel ) throws 
SQLException, ConfigurationException {
  
          return null;
      }
  
  
      public String getSubquery( Configuration tableConf, Configuration 
columnConf, Configuration modeConf )
          throws ConfigurationException {
  
          return null;
      }
  }
  
  
  
  1.1                  
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/components/modules/database/IfxSerialAutoIncrementModule.java
  
  Index: IfxSerialAutoIncrementModule.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
      [EMAIL PROTECTED]
  
   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  <[EMAIL PROTECTED]>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  
  package org.apache.cocoon.components.modules.database;
  
  import java.lang.Integer;
  import java.util.SortedSet;
  import java.util.Map;
  import java.sql.Connection;
  import java.sql.Statement;
  import java.sql.SQLException;
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.configuration.ConfigurationException;
  import org.apache.avalon.framework.thread.ThreadSafe;
  import com.informix.jdbc.IfxStatement;
  
  /**
   * Abstraction layer to encapsulate different DBMS behaviour for 
autoincrement columns.
   *
   * Here: Informix IUS 9.21 SERIAL columns
   * (need another one for SERIAL8 ones!)
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Christian Haul</a>
   * @version CVS $Id: IfxSerialAutoIncrementModule.java,v 1.1 2002/10/18 
14:04:26 haul Exp $
   */
  public class IfxSerialAutoIncrementModule implements AutoIncrementModule, 
ThreadSafe {
  
      public Object getPostValue( Configuration tableConf, Configuration 
columnConf, Configuration modeConf,
                                  Connection conn, Statement stmt, Map 
objectModel )
          throws SQLException, ConfigurationException {
  
          return new Integer(((com.informix.jdbc.IfxStatement) 
stmt).getSerial());
      };
  
  
      public boolean includeInQuery() { return false; };
  
  
      public boolean includeAsValue() { return false; };
  
  
      public Object getPreValue( Configuration tableConf, Configuration 
columnConf, Configuration modeConf,
                                 Connection conn, Map objectModel ) throws 
SQLException, ConfigurationException {
  
          return null;
      };
  
      public String getSubquery( Configuration tableConf, Configuration 
columnConf, Configuration modeConf )
          throws ConfigurationException {
  
          return null;
      };
  
  }
  
  
  
  1.1                  
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/components/modules/database/ManualAutoIncrementModule.java
  
  Index: ManualAutoIncrementModule.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
      [EMAIL PROTECTED]
  
   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  <[EMAIL PROTECTED]>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  
  package org.apache.cocoon.components.modules.database;
  
  import java.sql.Connection;
  import java.sql.Statement;
  import java.sql.PreparedStatement;
  import java.sql.ResultSet;
  import java.sql.SQLException;
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.configuration.ConfigurationException;
  import org.apache.avalon.framework.thread.ThreadSafe;
  import java.lang.Integer;
  import java.util.Map;
  import java.util.HashMap;
  import java.util.SortedSet;
  
  /**
   * Abstraction layer to encapsulate different DBMS behaviour for
   * autoincrement columns.
   *
   * Here: manual mode The new value is determined by doing a "select
   * max(column)+1 from table" query. With transactions and correct
   * isolation levels, this should to the trick almost everywhere.
   *
   * Note however, that the above query does not prevent a parallel
   * transaction to try to insert a row with the same ID since it
   * requires only shared locks. C.f. "Phantom Problem"
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Christian Haul</a>
   * @version CVS $Id: ManualAutoIncrementModule.java,v 1.1 2002/10/18 14:04:26 
haul Exp $
   */
  public class ManualAutoIncrementModule extends AbstractAutoIncrementModule 
implements ThreadSafe {
  
      private Map selectStatements = new HashMap();
  
  
      public Object getPostValue( Configuration tableConf, Configuration 
columnConf, Configuration modenConf,
                                  Connection conn, Statement stmt, Map 
objectModel )
          throws SQLException, ConfigurationException {
  
          return null;
      }
  
      public boolean includeInQuery( ) { return true; }
  
  
      public boolean includeAsValue( ) { return true; }
  
  
      public Object getPreValue( Configuration tableConf, Configuration 
columnConf, Configuration modeConf,
                                 Connection conn, Map objectModel )
          throws SQLException, ConfigurationException {
  
          /** Set the key value using SELECT MAX(keyname)+1 **/
          String tableName = tableConf.getAttribute("name","");
          String selectQuery = this.getSelectQuery(tableName, columnConf);
          PreparedStatement select_statement = 
conn.prepareStatement(selectQuery);
          ResultSet set = select_statement.executeQuery();
          set.next();
          int maxid = set.getInt("maxid");
          set.close();
          select_statement.close();
          if (getLogger().isDebugEnabled())
              getLogger().debug("autoincrementValue " + (maxid+1));
          return new Integer(maxid + 1);
      }
  
  
      public String getSubquery( Configuration tableConf, Configuration 
columnConf, Configuration modeConf )
          throws ConfigurationException {
  
          return null;
      }
  
  
      /**
       * Set the String representation of the MaxID lookup statement.  This is
       * mapped to the Configuration object itself, so if it doesn't exist,
       * it will be created.
       */
      protected final synchronized void setSelectQuery( String tableName, 
Configuration entry ) throws ConfigurationException {
  
          StringBuffer queryBuffer = new StringBuffer("SELECT max(");
          queryBuffer.append(entry.getAttribute("name"));
          queryBuffer.append(") AS maxid FROM ");
          queryBuffer.append(tableName);
  
          this.selectStatements.put(entry, queryBuffer.toString());
      }
  
  
      protected final synchronized String getSelectQuery( String tableName, 
Configuration entry ) throws ConfigurationException {
  
          String result = (String) this.selectStatements.get(entry);
          if (result == null) {
              setSelectQuery(tableName, entry);
              result = (String) this.selectStatements.get(entry);
          }
          return result;
      }
  
  }
  
  
  
  1.1                  
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/components/modules/database/MysqlAutoIncrementModule.java
  
  Index: MysqlAutoIncrementModule.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
      [EMAIL PROTECTED]
  
   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  <[EMAIL PROTECTED]>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  
  package org.apache.cocoon.components.modules.database;
  
  import java.lang.Integer;
  import java.sql.PreparedStatement;
  import java.sql.Connection;
  import java.sql.ResultSet;
  import java.sql.Statement;
  import java.sql.SQLException;
  import java.util.Map;
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.configuration.ConfigurationException;
  import org.apache.avalon.framework.thread.ThreadSafe;
  
  /**
   * Abstraction layer to encapsulate different DBMS behaviour for 
autoincrement columns.
   *
   * Here: [EMAIL PROTECTED] <a href="http://www.mysql.com";>MYSQL</a>} 
AUTO_INCREMENT columns
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Tim Myers</a>
   * @version CVS $Id: MysqlAutoIncrementModule.java,v 1.1 2002/10/18 14:04:26 
haul Exp $
   */
  public class MysqlAutoIncrementModule implements AutoIncrementModule, 
ThreadSafe {
  
      public Object getPostValue( Configuration tableConf, Configuration 
columnConf, Configuration modeConf,
                                  Connection conn, Statement stmt, Map 
objectModel )  throws SQLException, ConfigurationException {
  
          Integer id = null;
          /*
            // if mysql did support callable statements ...  i'm not sure what 
what would go here, maybe:
  
            CallableStatement callStmt = conn.prepareCall("? = {CALL 
LAST_INSERT_ID()}");
            callStmt.registerOutParameter(1, Types.INTEGER);
            ResultSet resultSet = callStmt.executeQuery();
          */
  
          PreparedStatement pstmt = conn.prepareStatement("SELECT 
LAST_INSERT_ID()");
          ResultSet resultSet = pstmt.executeQuery();
          while ( resultSet.next() ) {
              id = new Integer(resultSet.getInt(1));
          }
          resultSet.close();
  
          return id;
      }
  
  
      public boolean includeInQuery() { return false; }
  
  
      public boolean includeAsValue() { return false; }
  
  
      public Object getPreValue( Configuration tableConf, Configuration 
columnConf, Configuration modeConf,
                                 Connection conn, Map objectModel ) throws 
SQLException, ConfigurationException {
  
          return null;
      }
  
      public String getSubquery( Configuration tableConf, Configuration 
columnConf, Configuration modeConf )
          throws ConfigurationException {
  
          return null;
      }
  }
  
  
  
  
  1.1                  
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/components/modules/database/PgsqlAutoIncrementModule.java
  
  Index: PgsqlAutoIncrementModule.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
      [EMAIL PROTECTED]
  
   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  <[EMAIL PROTECTED]>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  
  package org.apache.cocoon.components.modules.database;
  
  import java.lang.Integer;
  import java.sql.PreparedStatement;
  import java.sql.Connection;
  import java.sql.ResultSet;
  import java.sql.Statement;
  import java.sql.SQLException;
  import java.util.Map;
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.configuration.ConfigurationException;
  import org.apache.avalon.framework.thread.ThreadSafe;
  
  /**
   * Abstraction layer to encapsulate different DBMS behaviour for 
autoincrement columns.
   *
   * Here: [EMAIL PROTECTED] <a href="http://www.postgres.org";>PostgreSQL</a>} 
SERIAL columns
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Philipp Hahn</a>
   * @version CVS $Id: PgsqlAutoIncrementModule.java,v 1.1 2002/10/18 14:04:26 
haul Exp $
   */
  public class PgsqlAutoIncrementModule implements AutoIncrementModule, 
ThreadSafe {
  
      public Object getPostValue( Configuration tableConf, Configuration 
columnConf, Configuration modeConf,
                                  Connection conn, Statement stmt, Map 
objectModel )  throws SQLException, ConfigurationException {
  
          Integer id = null;
          /*
            // Postgres does support callable statements ...  i'm not sure what 
what would go here, maybe:
  
            CallableStatement callStmt = conn.prepareCall("? = {CALL 
LAST_INSERT_ID()}");
            callStmt.registerOutParameter(1, Types.INTEGER);
            ResultSet resultSet = callStmt.executeQuery();
          */
  
        StringBuffer queryBuffer = new StringBuffer("SELECT currval('");
        queryBuffer.append(tableConf.getAttribute("name",""));
        queryBuffer.append('_');
        queryBuffer.append(columnConf.getAttribute("name"));
        queryBuffer.append("_seq')");
  
          PreparedStatement pstmt = 
conn.prepareStatement(queryBuffer.toString());
          ResultSet resultSet = pstmt.executeQuery();
          while ( resultSet.next() ) {
              id = new Integer(resultSet.getInt(1));
          }
          resultSet.close();
  
          return id;
      }
  
  
      public boolean includeInQuery() { return false; }
  
  
      public boolean includeAsValue() { return false; }
  
  
      public Object getPreValue( Configuration tableConf, Configuration 
columnConf, Configuration modeConf,
                                 Connection conn, Map objectModel ) throws 
SQLException, ConfigurationException {
  
          return null;
      }
  
      public String getSubquery( Configuration tableConf, Configuration 
columnConf, Configuration modeConf )
          throws ConfigurationException {
  
          return null;
      }
  }
  
  
  
  1.1                  
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/components/modules/database/package.html
  
  Index: package.html
  ===================================================================
  <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
  <html>
  <head>
    <title>output</title>
               
    <meta http-equiv="content-type"
   content="text/html; charset=ISO-8859-1">
  </head>
  <body>
     
  <h1>database<br>
  </h1>
     
  <p>Database modules provide an abstraction layer for different interfaces
  used by database management systems for autoincrement columns. The value
  can be obtained from the DBMS or some other source before or after the 
statement
  is executed. Or some code can be inserted into the query to direct the DBMS
  to use the next value of a sequence.</p>
    
  </body>
  </html>
  
  
  
  1.1                  
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/components/language/markup/xsp/EsqlConnection.java
  
  Index: EsqlConnection.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
      [EMAIL PROTECTED]
  
   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  <[EMAIL PROTECTED]>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  package org.apache.cocoon.components.language.markup.xsp;
  
  import java.sql.Connection;
  import java.util.Properties;
  import java.sql.SQLException;
  
  /**
   * This is wrapper to extend a java.sql.Conncetion implementation
   * for easier paging / limit facilities
   *
   * based on the orginal esql.xsl
   * @author <a href="mailto:[EMAIL PROTECTED]">Torsten Curdt</a>
   * @version CVS $Id: EsqlConnection.java,v 1.1 2002/10/18 14:04:26 haul Exp $
   */
  
  public class EsqlConnection implements Connection {
    public static final int LIMIT_METHOD_NOLIMIT = 0;
    public static final int LIMIT_METHOD_POSTGRESQL = 1;
    public static final int LIMIT_METHOD_MYSQL = 2;
    public static final int LIMIT_METHOD_JDBC = 3;
  
    public Connection connection = null;
  
    private String url = null;
    private Properties info = new Properties();
    private int limitMethod = LIMIT_METHOD_NOLIMIT;
    private boolean multipleResults = false;
  
  
      public boolean multipleResults() {
          return this.multipleResults;
      }
  
      /** It appears that some commercial DBMSs like Oracle and Informix
      * are broken in that they don't follow the JDBC standard and 
      * calls to getUpdateCount after getMoreResults result either in
      * an exception (Informix) or return the same value (i.e. not -1) (Oracle).
      * In addition, this feature is only useful with stored procedures.
      * Hence we disable it per default.
      **/
      public void setMultipleResults(String value) {
          if (value != null)
              this.multipleResults = ("true".equalsIgnoreCase(value) || 
"yes".equalsIgnoreCase(value));
      }
  
  
  
    public Properties getInfo() {
      return(info);
    }
  
    public String getUrl() {
      if (this.url == null)
        try {
          this.url=this.connection.getMetaData().getURL();
        } catch (SQLException e) {
        };
      return this.url;
    }
  
    public void setUrl( String url ) {
      this.url = url;
    }
  
    public void setProperty( String name, Object value ) {
      info.put(name,value);
    }
  
    public void setUser(String user) {
      setProperty("user",user);
    }
  
    public void setPassword(String password) {
      setProperty("password",password);
    }
  
    public int getLimitMethod() {
      return(limitMethod);
    }
  
    public void setLimitMethod( String method ) {
      if ("".equals(method) || "auto".equals(method) ) {
        String jdbcSource;
        try {
          jdbcSource = connection.getMetaData().getURL();
        } catch (Exception e) {
          throw new RuntimeException("Error accessing connection metadata: "+e);
        }
        if (jdbcSource.startsWith("jdbc:postgresql:")) {
          limitMethod = LIMIT_METHOD_POSTGRESQL;
        } else if (jdbcSource.startsWith("jdbc:mysql:")) {
          limitMethod = LIMIT_METHOD_MYSQL;
        } else if (jdbcSource.startsWith("jdbc:sybase:")) {
          limitMethod = LIMIT_METHOD_JDBC;
        }
        else {
          throw new RuntimeException("Cannot guess limit method from jdbc url: 
" + method);
        }
      }
      else if ("postgresql".equals(method)) {
        limitMethod = LIMIT_METHOD_POSTGRESQL;
      } else if ("mysql".equals(method)) {
        limitMethod = LIMIT_METHOD_MYSQL;
      } else if ("jdbc".equals(method)) {
        limitMethod = LIMIT_METHOD_JDBC;
      } else {
        throw new RuntimeException("Unknown limit method: " + method);
      }
    }
  
  
    /* */
  
    public java.sql.Statement createStatement() throws SQLException {
      return(connection.createStatement());
    }
  
    public java.sql.Statement createStatement(int i1, int i2) throws 
SQLException {
      return(connection.createStatement(i1, i2));
    }
  
    public java.sql.PreparedStatement prepareStatement(String s) throws 
SQLException {
      return(connection.prepareStatement(s));
    }
  
    public java.sql.PreparedStatement prepareStatement(String s, int i1, int 
i2) throws SQLException {
      return(connection.prepareStatement(s, i1, i2));
    }
  
  
    public void close() throws SQLException {
      connection.close();
    }
  
    public void commit() throws SQLException {
      connection.commit();
    }
  
    public void rollback() throws SQLException {
      connection.rollback();
    }
  
    public boolean getAutoCommit() throws SQLException {
      return(connection.getAutoCommit());
    }
  
    public void setAutoCommit(boolean autocommit) throws SQLException {
      connection.setAutoCommit(autocommit);
    }
  
    public void setTransactionIsolation(int i)  throws SQLException {
      connection.setTransactionIsolation(i);
    }
  
    public int getTransactionIsolation()  throws SQLException {
      return(connection.getTransactionIsolation());
    }
  
    public String getCatalog()  throws SQLException {
      return(connection.getCatalog());
    }
  
    public java.sql.SQLWarning getWarnings()  throws SQLException {
      return(connection.getWarnings());
    }
  
    public java.util.Map getTypeMap() throws SQLException {
      return(connection.getTypeMap());
    }
  
    public boolean isClosed() throws SQLException {
      return(connection.isClosed());
    }
  
    public java.sql.DatabaseMetaData getMetaData() throws SQLException {
      return(connection.getMetaData());
    }
  
    public void setCatalog(String s) throws SQLException {
      connection.setCatalog(s);
    }
  
    public void setTypeMap(java.util.Map m) throws SQLException {
      connection.setTypeMap(m);
    }
  
    public void setReadOnly(boolean b) throws SQLException {
      connection.setReadOnly(b);
    }
  
    public void clearWarnings() throws SQLException {
      connection.clearWarnings();
    }
  
    public boolean isReadOnly() throws SQLException {
      return(connection.isReadOnly());
    }
  
    public String nativeSQL(String s) throws SQLException {
      return(connection.nativeSQL(s));
    }
  
    public java.sql.CallableStatement prepareCall(String s) throws SQLException 
{
      return(connection.prepareCall(s));
    }
  
    public java.sql.CallableStatement prepareCall(String s, int i1, int i2) 
throws SQLException {
      return(connection.prepareCall(s,i1,i2));
    }
  
    /* @JDBC3_START@
      public void setHoldability(int holdability)
          throws SQLException
      {
          connection.setHoldability(holdability);
      }
  
      public int getHoldability()
          throws SQLException
      {
          return connection.getHoldability();
      }
  
      public java.sql.Savepoint setSavepoint()
          throws SQLException
      {
          return connection.setSavepoint();
      }
  
      public java.sql.Savepoint setSavepoint(String savepoint)
          throws SQLException
      {
          return connection.setSavepoint(savepoint);
      }
  
      public void rollback(java.sql.Savepoint savepoint)
          throws SQLException
      {
          connection.rollback(savepoint);
      }
  
      public void releaseSavepoint(java.sql.Savepoint savepoint)
          throws SQLException
      {
          connection.releaseSavepoint(savepoint);
      }
  
      public java.sql.Statement createStatement(int resulSetType,
                                             int resultSetConcurrency,
                                             int resultSetHoldability)
          throws SQLException
      {
          return connection.createStatement(resulSetType, resultSetConcurrency, 
resultSetHoldability);
      }
  
      public java.sql.PreparedStatement prepareStatement(String sql,
                                          int resulSetType,
                                          int resultSetConcurrency,
                                          int resultSetHoldability)
          throws SQLException
      {
          return connection.prepareStatement(sql, resulSetType, 
resultSetConcurrency, resultSetHoldability);
      }
  
      public java.sql.CallableStatement prepareCall(String sql,
                                          int resulSetType,
                                          int resultSetConcurrency,
                                          int resultSetHoldability)
          throws SQLException
      {
          return connection.prepareCall(sql, resulSetType, 
resultSetConcurrency, resultSetHoldability);
      }
  
      public java.sql.PreparedStatement prepareStatement(String sql,
                                          int autoGeneratedKeys)
          throws SQLException
      {
          return connection.prepareStatement(sql, autoGeneratedKeys);
      }
  
      public java.sql.PreparedStatement prepareStatement(String sql,
                                          int[] columnIndexes)
          throws SQLException
      {
          return connection.prepareStatement(sql, columnIndexes);
      }
  
      public java.sql.PreparedStatement prepareStatement(String sql,
                                          String[] columnNames)
          throws SQLException
      {
          return connection.prepareStatement(sql, columnNames);
      }
  @JDBC3_END@ */
  
  }
  
  
  
  
  1.1                  
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/components/language/markup/xsp/EsqlConnectionCocoon2.java
  
  Index: EsqlConnectionCocoon2.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
      [EMAIL PROTECTED]
  
   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  <[EMAIL PROTECTED]>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  package org.apache.cocoon.components.language.markup.xsp;
  
  import org.apache.avalon.excalibur.datasource.DataSourceComponent;
  
  /**
   * This is the Cocoon2 specific part of an EsqlConnection.
   * This should only be in the C2 codebase
   *
   * based on the orginal esql.xsl
   * @author <a href="mailto:[EMAIL PROTECTED]">Torsten Curdt</a>
   * @version CVS $Id: EsqlConnectionCocoon2.java,v 1.1 2002/10/18 14:04:26 
haul Exp $
   */
  
  public class EsqlConnectionCocoon2 extends EsqlConnection {
    public DataSourceComponent datasource = null;
  }
  
  
  
  1.1                  
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/components/language/markup/xsp/EsqlHelper.java
  
  Index: EsqlHelper.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
      [EMAIL PROTECTED]
  
   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  <[EMAIL PROTECTED]>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  package org.apache.cocoon.components.language.markup.xsp;
  
  import java.io.BufferedInputStream;
  import java.io.BufferedReader;
  import java.io.Reader;
  import java.sql.CallableStatement;
  import java.sql.ResultSet;
  import java.io.InputStream;
  import java.sql.Blob;
  import java.sql.Clob;
  import java.sql.Types;
  
  /**
   * This is a helper class to remove redundant code in
   * esql pages
   *
   * based on the orginal esql.xsl
   * @author <a href="mailto:[EMAIL PROTECTED]">Torsten Curdt</a>
   * @version CVS $Id: EsqlHelper.java,v 1.1 2002/10/18 14:04:26 haul Exp $
   */
  
  public class EsqlHelper {
  
  
      /** returns byte array from BLOB
       */
      public final static byte[] getBlob(ResultSet set, String column) throws 
RuntimeException {
          
          byte[] result = null;
          try {
              result = EsqlHelper.getBlob(set,set.findColumn(column));
          } catch (Exception e) {
              throw new RuntimeException("Error getting blob data: " + 
e.getMessage());
          }
          return result;
      }
  
      /** returns byte array from BLOB
       */
      public final static byte[] getBlob(ResultSet set, int column) throws 
java.lang.Exception {
          
          InputStream reader = null;
          byte[] buffer = null;
      
          try {
              if (set.getMetaData().getColumnType(column)==java.sql.Types.BLOB) 
{
                  Blob dbBlob = set.getBlob(column);
                  int length = (int) dbBlob.length();
                  reader = dbBlob.getBinaryStream();
                  buffer = new byte[length];
                  reader.read(buffer);
                  reader.close();
                  if (reader != null)
                      reader.close();
                  if (buffer == null)
                      return null;
                  return buffer;
              } else {           
                  return set.getString(column).getBytes();
              }
          } catch ( Exception e) {
              throw new RuntimeException("Error getting blob data: " + 
e.getMessage());
          }
      }
  
      /** returns byte array from BLOB
       */
      public final static byte[] getBlob(CallableStatement cs, int column) 
throws java.lang.Exception {
          
          InputStream reader = null;
          byte[] buffer = null;
      
          try {
              Blob dbBlob = cs.getBlob(column);
              int length = (int) dbBlob.length();
              reader = dbBlob.getBinaryStream();
              buffer = new byte[length];
              reader.read(buffer);
              reader.close();
              if (reader != null)
                  reader.close();
              if (buffer == null)
                  return null;
              return buffer;
          } catch ( Exception e) {
              throw new RuntimeException("Error getting blob data: " + 
e.getMessage());
          }
      }
  
      /** returns Unicode encoded string from CLOB or String column 
       */
      public final static String getStringOrClob(ResultSet set, String column) 
throws RuntimeException {
          
          String result = null;
          try {
              result = EsqlHelper.getStringOrClob(set,set.findColumn(column));
          } 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(ResultSet set, int column) 
throws java.lang.Exception {
          
          Reader reader = null;
          char[] buffer = null;
      
          try {
              if (set.getMetaData().getColumnType(column)==java.sql.Types.CLOB) 
{
                  Clob dbClob = set.getClob(column);
                  int length = (int) dbClob.length();
                  reader = new BufferedReader(dbClob.getCharacterStream());
                  buffer = new char[length];
                  reader.read(buffer);
                  reader.close();
                  if (reader != null)
                      reader.close();
                  if (buffer == null)
                      return "";
                  return new String(buffer);
              } else {           
                  return set.getString(column);
              }
          } catch ( Exception e) {
              throw new RuntimeException("Error getting clob data: " + 
e.getMessage());
          }
      }
  
      /** returns Unicode encoded string from CLOB or String column 
       */
      public final static String getStringOrClob(CallableStatement cs, int 
column) throws java.lang.Exception {
          
          Reader reader = null;
          char[] buffer = null;
      
          try {
              Clob dbClob = cs.getClob(column);
              int length = (int) dbClob.length();
              reader = new BufferedReader(dbClob.getCharacterStream());
              buffer = new char[length];
              reader.read(buffer);
              reader.close();
              if (reader != null)
                  reader.close();
              if (buffer == null)
                  return "";
              return new String(buffer);
          } catch ( Exception e) {
              throw new RuntimeException("Error getting clob data: " + 
e.getMessage());
          }
      }
  
  
      /** returns ascii string from CLOB or String column 
       */
        public final static String getAscii(ResultSet set, String column) 
throws RuntimeException {
  
            String result = null;
            try {
                result = EsqlHelper.getAscii(set,set.findColumn(column));
            } 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, int column) {
          InputStream asciiStream = null;
          String result = null;
  
          try {
              if (set.getMetaData().getColumnType(column) == Types.CLOB) {
                  byte[] buffer = null;
                  Clob dbClob = set.getClob(column);
                  int length = (int) dbClob.length();
                  asciiStream = new 
BufferedInputStream(dbClob.getAsciiStream());
                  buffer = new byte[length];
                  asciiStream.read(buffer);
                  asciiStream.close();
                  result = (buffer!=null? new String(buffer) : null);
              } else {
                  result = set.getString(column);
              }
          } catch (Exception e) {
              throw new RuntimeException("Error getting clob data: " + 
e.getMessage());
          } finally {
              if (asciiStream != null) try {asciiStream.close();} catch 
(Exception ase) {
                  throw new RuntimeException("Error closing clob stream: " + 
ase.getMessage());
              }
          }
          
          return result;
        }
  
      /** returns ascii string from CLOB or String column 
       */
      public final static String getAscii(CallableStatement cs, int column) {
          InputStream asciiStream = null;
          String result = null;
  
          try {
              byte[] buffer = null;
              Clob dbClob = cs.getClob(column);
              int length = (int) dbClob.length();
              asciiStream = new BufferedInputStream(dbClob.getAsciiStream());
              buffer = new byte[length];
              asciiStream.read(buffer);
              asciiStream.close();
              result = (buffer!=null? new String(buffer) : null);
          } catch (Exception e) {
              throw new RuntimeException("Error getting clob data: " + 
e.getMessage());
          } finally {
              if (asciiStream != null) try {asciiStream.close();} catch 
(Exception ase) {
                  throw new RuntimeException("Error closing clob stream: " + 
ase.getMessage());
              }
          }
          
          return result;
        }
  
        public final static String getStringFromByteArray(byte[] bytes, String 
encoding) {
          if (bytes != null) {
              try {
                  return new String(bytes,encoding);
              } catch (java.io.UnsupportedEncodingException uee) {
                  throw new RuntimeException("Unsupported Encoding Exception: " 
+ uee.getMessage());
              }
          }
          else {
              return("");
          }
        }
  
  }
  
  
  
  1.1                  
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/components/language/markup/xsp/EsqlQuery.java
  
  Index: EsqlQuery.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
      [EMAIL PROTECTED]
  
   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  <[EMAIL PROTECTED]>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  package org.apache.cocoon.components.language.markup.xsp;
  
  import java.sql.Connection;
  import java.sql.Statement;
  import java.sql.PreparedStatement;
  import java.sql.CallableStatement;
  import java.sql.ResultSet;
  import java.sql.ResultSetMetaData;
  import java.sql.SQLException;
  import java.util.ArrayList;
  import java.lang.reflect.Field;
  /**
   * This helper class takes care of contstructing queries
   * and cursor positioning (paging) for all different kinds
   * of databases
   *
   * based on the orginal esql.xsl
   * @author <a href="mailto:[EMAIL PROTECTED]">Torsten Curdt</a>
   * @version CVS $Id: EsqlQuery.java,v 1.1 2002/10/18 14:04:26 haul Exp $
   */
  
  public class EsqlQuery {
    private static final int UPDATE_COUNT_UNSET = -2;
  
    private Connection connection = null;
    private Statement statement = null;
    private PreparedStatement preparedStatement = null;
    private ResultSet resultSet = null;
    private ResultSetMetaData resultSetMetaData = null;
    private int updateCount = EsqlQuery.UPDATE_COUNT_UNSET;
    private int updateCountCount = 0;
    private int resultCount = 0;
    private boolean hasResultSet = false;
    private boolean resultSetValid = false;
    private int position = -1;
    private int maxRows = -1;
    private int skipRows = 0;
    private boolean keepgoing = true;
  
    private ArrayList groups = null;
    private int groupLevel = -1;
    private int changeLevel = -1;
  
    private String query;
    private int limitMethod;
  
    public EsqlQuery( EsqlConnection connection, String query ) {
      this.connection = connection;
      this.limitMethod = connection.getLimitMethod();
      this.query = query;
    }
  
    public EsqlQuery( ResultSet aResultSet ) {
      this.connection = null;
      this.statement = null;
      this.query = null;
      this.resultSetValid = true;
      this.resultSet = aResultSet;
      this.hasResultSet = (this.resultSet != null);
    }
  
  
    class EsqlGroup {
      public String var = null;
      public Object value = null;
          
      EsqlGroup ( String var, Object value ) {
        this.var = var;
        this.value = value;
        }
    }
  
    public int getSkipRows() {
      return(skipRows);
    }
  
    public void setSkipRows( int i ) {
      this.skipRows = i;
    }
  
    public int getMaxRows() {
      return(maxRows);
    }
  
    public void setMaxRows( int i ) {
      this.maxRows = i;
    }
  
    public int getCurrentRow() {
      return(position);
    }
  
    public String getQueryString() {
      switch(limitMethod) {
        case EsqlConnection.LIMIT_METHOD_POSTGRESQL:
          if (skipRows > 0) {
            if (maxRows > -1) {
              return(new StringBuffer(query).append(" LIMIT 
").append(maxRows).append(",").append(skipRows).toString());
            }
            else {
              return(new StringBuffer(query).append(" OFFSET 
").append(skipRows).toString());
            }
          }
          else {
            if (maxRows > -1) {
              return(new StringBuffer(query).append(" LIMIT 
").append(maxRows).toString());
            }
            else {
              return(query);
            }
          }
        case EsqlConnection.LIMIT_METHOD_MYSQL:
          if (skipRows > 0) {
            if (maxRows > -1) {
              return(new StringBuffer(query).append(" LIMIT 
").append(skipRows).append(",").append(maxRows).toString());
            }
            else {
              throw new RuntimeException("MySQL does not support a skip of rows 
only");
            }
          }
          else {
            if (maxRows > -1) {
              return(new StringBuffer(query).append(" LIMIT 
").append(maxRows).toString());
            }
            else {
              return(query);
            }
          }
        default:
          return(query);
      }
    }
  
    public PreparedStatement prepareStatement() throws SQLException {
      switch(limitMethod) {
      case EsqlConnection.LIMIT_METHOD_POSTGRESQL:
      case EsqlConnection.LIMIT_METHOD_MYSQL:
          preparedStatement = connection.prepareStatement(getQueryString() );
          break;
      case EsqlConnection.LIMIT_METHOD_JDBC:
          // Produce scrollable ResultSet and skip rows with 
ResultSet.absolute(skipRows).
          // With SQL Server, statement.getResultSet() throws
          // java.sql.SQLException: [Microsoft][SQLServer 2000 Driver for 
JDBC]Error setting up static cursor cache.
          // Same error with TYPE_SCROLL_SENSITIVE.
          preparedStatement = connection.prepareStatement( getQueryString(),
                                                           
ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
          break;
      case EsqlConnection.LIMIT_METHOD_NOLIMIT:
      default:
          // maxRows can be set without the limit method being set - it 
defaults to LIMIT_METHOD_NOLIMIT
          // which is not such a good name as its really another way of 
limiting using JDBC.
          // Produce non-scrollable ResultSet and skip rows with multiple 
ResultSet.next().
          preparedStatement = connection.prepareStatement(getQueryString() );
          break;
      }
      statement = preparedStatement;
      return(preparedStatement);
    }
  
  
    public CallableStatement prepareCall() throws SQLException {
      switch(limitMethod) {
      case EsqlConnection.LIMIT_METHOD_POSTGRESQL:
      case EsqlConnection.LIMIT_METHOD_MYSQL:
          preparedStatement = connection.prepareCall( getQueryString() );
          break;
      case EsqlConnection.LIMIT_METHOD_JDBC:
          preparedStatement = connection.prepareCall( getQueryString(), 
ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
          break;
      case EsqlConnection.LIMIT_METHOD_NOLIMIT:
       default:
          preparedStatement = connection.prepareCall( getQueryString() );
      };
      statement = preparedStatement;
      return((CallableStatement)preparedStatement);
    }
  
    public PreparedStatement getPreparedStatement() {
      return(preparedStatement);
    }
  
    public CallableStatement getCallableStatement() {
      return((CallableStatement) preparedStatement);
    }
  
    public ResultSet getResultSet() {
      return(resultSet);
    }
  
    public boolean nextRow() throws SQLException {
      position++;
      return(resultSet.next());
    }
  
    public boolean keepGoing() {
      return(keepgoing);
    }
  
    public void setKeepGoing( boolean still ) {
      keepgoing = still;
    }
  
      public void groupLevelPlusPlus() {
          this.groupLevel++;
      }
  
      public void groupLevelMinusMinus() {
          this.groupLevel--;
      }
  
      public boolean groupLevelExists() {
          return (this.groups != null && this.groups.size() >= 
this.groupLevel+1 && this.groups.get(this.groupLevel) != null);
      }
  
      public void setGroupingVar( String key ) throws SQLException {
          if (this.groups == null)
              this.groups = new ArrayList(1);
          this.groups.ensureCapacity(this.groupLevel);
          this.groups.add(this.groupLevel, new EsqlGroup(key, 
this.getResultSet().getObject(key)));
      }
  
      public boolean hasGroupingVarChanged() throws SQLException {
          if (this.changeLevel != -1) {
              if (this.changeLevel < this.groupLevel) {
                  return true;
              } else {
                  this.changeLevel = -1;
                  return true;
              }
          } else {
              boolean result = false;
              // need to check the complete hierarchy of nested groups for 
changes
              for (int i = 0; i <= this.groupLevel; i++) {
                  Object tmp = 
this.getResultSet().getObject(((EsqlGroup)this.groups.get(i)).var);
                  if (!tmp.equals(((EsqlGroup)this.groups.get(i)).value)) {
                      ((EsqlGroup)this.groups.get(i)).value = tmp;
                      result = true;
                      if (this.changeLevel == -1 && this.groupLevel != i)
                          this.changeLevel = i;
                  }
              }
              return result;
          }
      }
  
    public ResultSetMetaData getResultSetMetaData() {
      return(resultSetMetaData);
    }
  
    public Statement createStatement() throws SQLException {
      switch(limitMethod) {
        case EsqlConnection.LIMIT_METHOD_JDBC:
          statement = 
connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, 
ResultSet.CONCUR_READ_ONLY);
          break;
        default:
          statement = connection.createStatement();
      };
      return(statement);
    }
  
    public Statement getStatement() {
      return(statement);
    }
  
    public int getUpdateCount() throws SQLException {
      return this.updateCount;
    }
  
    public int getUpdateCountCount() {
      return this.updateCountCount;
    }
  
    public int getResultCount() {
      return this.resultCount;
    }
  
      /**
       * retrieve next result, check whether it is an result set or an
       * update count. Set instance vars accordingly and update
       * counters.
       */
    public boolean getMoreResults() throws SQLException {
      if (this.statement==null)
          return false;
      this.hasResultSet = this.statement.getMoreResults();
      this.resultSetValid=false;
      this.adjustCounts();
      return (this.hasResultSet || (this.updateCount>-1));
    }
  
  
      /**
       * update counters for result sets and update counts
       */
      protected void adjustCounts() throws SQLException {
          this.updateCount=this.statement.getUpdateCount();
          if (this.hasResultSet) {
              this.resultCount++;
          } else {
              this.updateCountCount++;
          }
      };
  
    public boolean execute() throws SQLException {
        return this.execute(false);
    }
  
    public boolean execute( int resultSetFromObject ) throws SQLException {
        hasResultSet = this.execute(false);
        resultSet = (ResultSet) ((CallableStatement) 
preparedStatement).getObject(resultSetFromObject);
        resultSetValid = true;
        return hasResultSet;
    }
  
    /**
     * some brain dead DBMSs (Informix) don't like their callable
     * statements to be 'execute'd but require 'executeQuery' instead.
     */
    public boolean execute( boolean needsQuery ) throws SQLException {
        if ( needsQuery ) {
            if (preparedStatement != null) {
                resultSet = preparedStatement.executeQuery();
            }
            else {
                resultSet = statement.executeQuery( getQueryString() );
            }
            hasResultSet = (resultSet != null);
            resultSetValid = true;
        } else {
            if (preparedStatement != null) {
                hasResultSet = preparedStatement.execute();
            }
            else {
                hasResultSet = statement.execute( getQueryString() );
            }
            resultSetValid = false;
        }
        this.adjustCounts();
        return(hasResultSet);
    }
  
    public boolean hasResultSet() {
      return(this.hasResultSet);
    }
  
    public int rowCount() throws SQLException {
      switch(limitMethod) {
        case EsqlConnection.LIMIT_METHOD_JDBC:
            // TC: I'm not quite sure if synchronized is really necessary since
            // the XSP page will be poolable
            synchronized (resultSet) {
              int currentRow = resultSet.getRow();
              resultSet.last();
              int count = resultSet.getRow();
              if (currentRow > 0) {
                resultSet.absolute(currentRow);
              }
              else {
                resultSet.first();
               resultSet.relative(-1);
              }
              return(count);
            }
        default:
          // select count(*)
          throw new RuntimeException("not yet implemented");
      }
    }
  
    public void getResultRows() throws SQLException {
      if ( !resultSetValid ) {
          resultSet = statement.getResultSet();
      }
      resultSetMetaData = resultSet.getMetaData();
      position = 0;
      if (skipRows > 0) {
        switch(limitMethod) {
          case EsqlConnection.LIMIT_METHOD_POSTGRESQL:
            // in clause
            position = skipRows;
            break;
          case EsqlConnection.LIMIT_METHOD_MYSQL:
            // in clause
            position = skipRows;
            break;
          case EsqlConnection.LIMIT_METHOD_JDBC:
            resultSet.absolute(skipRows);
            position = skipRows;
            break;
          default:
            while (resultSet.next()) {
              position++;
              if (position == skipRows) {
                 break;
              }
            }
        };
      }
    }
  
  }
  
  
  
  1.1                  
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/components/language/markup/xsp/java/esql.xsl
  
  Index: esql.xsl
  ===================================================================
  <?xml version="1.0"?><!-- -*- xsl -*- -->
  
  <!-- $Id: esql.xsl,v 1.1 2002/10/18 14:04:27 haul Exp $-->
  <!--
  
   ============================================================================
                     The Apache Software License, Version 1.2
   ============================================================================
  
   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 "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
      [EMAIL PROTECTED]
  
   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  <[EMAIL PROTECTED]>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  -->
  
  <!--
   * ESQL Logicsheet
   *
   * @author ?
   * @version CVS $Revision: 1.1 $ $Date: 2002/10/18 14:04:27 $
  -->
  
  <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
    xmlns:xsp="http://apache.org/xsp";
    xmlns:esql="http://apache.org/cocoon/SQL/v2";
    xmlns:xspdoc="http://apache.org/cocoon/XSPDoc/v1";
  >
  
  <xsl:param name="XSP-ENVIRONMENT"/>
  <xsl:param name="XSP-VERSION"/>
  <xsl:param name="filename"/>
  <xsl:param name="language"/>
  
  <xsl:variable name="environment">Cocoon 2</xsl:variable>
  <xsl:variable name="xsp-namespace-uri">http://apache.org/xsp</xsl:variable>
  
  <xsl:variable name="prefix">esql</xsl:variable>
  
  <xsl:template name="get-nested-content">
    <xsl:param name="content"/>
    <xsl:choose>
      <xsl:when test="$content/xsp:text">"<xsl:value-of 
select="$content"/>"</xsl:when>
      <xsl:when test="$content/*">
        <xsl:apply-templates select="$content/*"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$content"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
  
  <xsl:template name="get-nested-string">
    <xsl:param name="content"/>
    <xsl:choose>
    <!-- if $content has sub-elements, concatenate them -->
      <xsl:when test="$content/*">
        ""
        <xsl:for-each select="$content/node()">
          <xsl:choose>
            <xsl:when test="name(.)">
            <!-- element -->
              <xsl:choose>
                <xsl:when test="namespace-uri(.)='http://apache.org/xsp' and 
local-name(.)='text'">
                <!-- xsp:text element -->
                  + "<xsl:value-of select="translate(.,'&#9;&#10;&#13;','   
')"/>"
                </xsl:when>
                <xsl:otherwise>
                <!-- other elements -->
                  + <xsl:apply-templates select="."/>
                </xsl:otherwise>
              </xsl:choose>
            </xsl:when>
            <xsl:otherwise>
            <!-- text node -->
              + "<xsl:value-of select="translate(.,'&#9;&#10;&#13;','   ')"/>"
            </xsl:otherwise>
          </xsl:choose>
        </xsl:for-each>
      </xsl:when>
      <!-- else return the text value of $content -->
      <xsl:otherwise>"<xsl:value-of 
select="normalize-space($content)"/>"</xsl:otherwise>
    </xsl:choose>
  </xsl:template>
  
  
    <xsl:template name="get-parameter">
      <xsl:param name="name"/>
      <xsl:param name="default"/>
      <xsl:param name="required">false</xsl:param>
  
      <xsl:variable name="qname">
        <xsl:value-of select="concat($prefix, ':param')"/>
      </xsl:variable>
  
      <xsl:choose>
        <xsl:when test="@*[name(.) = $name]">"<xsl:value-of select="@*[name(.) 
= $name]"/>"</xsl:when>
        <xsl:when test="(*[name(.) = $qname])[EMAIL PROTECTED] = $name]">
          <xsl:call-template name="get-nested-content">
            <xsl:with-param name="content"
                            select="(*[name(.) = $qname])[EMAIL PROTECTED] = 
$name]"/>
          </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
          <xsl:choose>
            <xsl:when test="string-length($default) = 0">
              <xsl:choose>
                <xsl:when test="$required = 'true'">
                  <xsl:call-template name="error">
                    <xsl:with-param name="message">[Logicsheet processor]
  Parameter '<xsl:value-of select="$name"/>' missing in dynamic tag 
&lt;<xsl:value-of select="name(.)"/>&gt;
                    </xsl:with-param>
                  </xsl:call-template>
                </xsl:when>
                <xsl:otherwise>""</xsl:otherwise>
              </xsl:choose>
            </xsl:when>
            <xsl:otherwise><xsl:copy-of select="$default"/></xsl:otherwise>
          </xsl:choose>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:template>
  
  <xsl:template match="xsp:page">
    <xsp:page>
      <xsl:apply-templates select="@*"/>
      <xsp:structure>
        <xsp:include>java.sql.DriverManager</xsp:include>
        <xsp:include>java.sql.Connection</xsp:include>
        <xsp:include>java.sql.Statement</xsp:include>
        <xsp:include>java.sql.PreparedStatement</xsp:include>
        <xsp:include>java.sql.CallableStatement</xsp:include>
        <xsp:include>java.sql.ResultSet</xsp:include>
        <xsp:include>java.sql.ResultSetMetaData</xsp:include>
        <xsp:include>java.sql.Struct</xsp:include>
        <xsp:include>java.sql.SQLException</xsp:include>
        <xsp:include>java.sql.Clob</xsp:include>
        <xsp:include>java.sql.Blob</xsp:include>
        <xsp:include>java.text.SimpleDateFormat</xsp:include>
        <xsp:include>java.text.DecimalFormat</xsp:include>
        <xsp:include>java.io.StringWriter</xsp:include>
        <xsp:include>java.io.PrintWriter</xsp:include>
        <xsp:include>java.io.BufferedInputStream</xsp:include>
        <xsp:include>java.io.InputStream</xsp:include>
        <xsp:include>java.util.Set</xsp:include>
        <xsp:include>java.util.List</xsp:include>
        <xsp:include>java.util.Iterator</xsp:include>
        <xsp:include>java.util.ListIterator</xsp:include>
        <xsp:include>java.math.BigDecimal</xsp:include>
        <xsp:include>java.sql.Struct</xsp:include>
        <xsp:include>java.sql.Types</xsp:include>
        
<xsp:include>org.apache.cocoon.components.language.markup.xsp.EsqlHelper</xsp:include>
        
<xsp:include>org.apache.cocoon.components.language.markup.xsp.EsqlQuery</xsp:include>
        
<xsp:include>org.apache.cocoon.components.language.markup.xsp.EsqlConnection</xsp:include>
        
<xsp:include>org.apache.cocoon.components.language.markup.xsp.EsqlConnectionCocoon2</xsp:include>
        
<xsp:include>org.apache.cocoon.components.language.markup.xsp.XSPUtil</xsp:include>
        <xsl:if test=".//esql:connection/esql:pool">
          
<xsp:include>org.apache.avalon.excalibur.datasource.DataSourceComponent</xsp:include>
        </xsl:if>
      </xsp:structure>
      <xsp:logic>
        <xsl:call-template name="variables"><xsl:with-param name="modifier" 
select="'private'"/></xsl:call-template>
  
        <xsl:if test=".//esql:connection/esql:pool">
              private static ComponentSelector _esql_selector = null;
  
              protected ComponentSelector _esql_get_selector() throws 
org.apache.avalon.framework.component.ComponentException {
                if (_esql_selector == null) {
                  try {
                    _esql_selector = (ComponentSelector) 
manager.lookup(DataSourceComponent.ROLE + "Selector");
                  } catch (ComponentException cme) {
                    getLogger().error("Could not look up the datasource 
component", cme);
                  }
                }
                return _esql_selector;
              }
        </xsl:if>
  
              protected void _esql_printObject ( Object obj, AttributesImpl 
xspAttr) throws SAXException
              {
                 if ( obj instanceof List) {
             ListIterator j=((List)obj).listIterator();
             <xsp:element name="sql-list">
                       <xsp:logic>
                         while (j.hasNext()){
                        <xsp:element name="sql-list-item">
                          <xsp:attribute 
name="pos"><xsp:expr>j.nextIndex()</xsp:expr></xsp:attribute>
                          
<xsp:logic>this._esql_printObject(j.next(),xspAttr);</xsp:logic>
                        </xsp:element>
                         };
                       </xsp:logic>
                     </xsp:element>
                 } else if ( obj instanceof Set ) {
              Iterator j=((Set)obj).iterator();
              <xsp:element name="sql-set">
                        <xsp:logic>
                          while (j.hasNext()){
                             <xsp:element name="sql-set-item">
                   
<xsp:logic>this._esql_printObject(j.next(),xspAttr);</xsp:logic>
                     </xsp:element>
                          };
                        </xsp:logic>
                      </xsp:element>
             } else {
                <xsp:content><xsp:expr>obj</xsp:expr></xsp:content>;
             }
          }
      </xsp:logic>
      <xsl:apply-templates/>
    </xsp:page>
  </xsl:template>
  
  <xsl:template name="variables">
    <xsl:param name="modifier" select="''"/>
    <xsp:logic>
      <xsl:value-of select="$modifier"/> Stack _esql_connections = new Stack();
      <xsl:value-of select="$modifier"/> EsqlConnectionCocoon2 _esql_connection 
= null;
      <xsl:value-of select="$modifier"/> Stack _esql_queries = new Stack();
      <xsl:value-of select="$modifier"/> EsqlQuery _esql_query = null;
      <xsl:value-of select="$modifier"/> SQLException _esql_exception = null;
      <xsl:value-of select="$modifier"/> StringWriter _esql_exception_writer = 
null;
    </xsp:logic>
  </xsl:template>
  
  <xsl:template match="xsp:page/*[not(self::xsp:*)]">
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:template>
  
  <xsl:template match="esql:connection">
    <xsl:variable name="driver"><xsl:call-template 
name="get-nested-string"><xsl:with-param name="content" 
select="esql:driver"/></xsl:call-template></xsl:variable>
    <xsl:variable name="dburl"><xsl:call-template 
name="get-nested-string"><xsl:with-param name="content" 
select="esql:dburl"/></xsl:call-template></xsl:variable>
    <xsl:variable name="username"><xsl:call-template 
name="get-nested-string"><xsl:with-param name="content" 
select="esql:username"/></xsl:call-template></xsl:variable>
    <xsl:variable name="password"><xsl:call-template 
name="get-nested-string"><xsl:with-param name="content" 
select="esql:password"/></xsl:call-template></xsl:variable>
    <xsl:variable name="pool"><xsl:call-template 
name="get-nested-string"><xsl:with-param name="content" 
select="esql:pool"/></xsl:call-template></xsl:variable>
    <xsl:variable name="autocommit"><xsl:call-template 
name="get-nested-string"><xsl:with-param name="content" 
select="esql:autocommit"/></xsl:call-template></xsl:variable>
    <xsl:variable name="use-limit-clause"><xsl:call-template 
name="get-nested-string"><xsl:with-param name="content" 
select="esql:use-limit-clause"/></xsl:call-template></xsl:variable>
    <xsl:variable name="allow-multiple-results"><xsl:call-template 
name="get-nested-string"><xsl:with-param name="content" 
select="esql:allow-multiple-results"/></xsl:call-template></xsl:variable>
    <xsp:logic>
      if (_esql_connection != null) {
        _esql_connections.push(_esql_connection);
      }
      _esql_connection = new EsqlConnectionCocoon2();
      try {
        <xsl:choose>
          <xsl:when test="esql:pool">
            try {
              _esql_connection.datasource = (DataSourceComponent) 
_esql_get_selector().select(String.valueOf(<xsl:copy-of select="$pool"/>));
              _esql_connection.connection = 
_esql_connection.datasource.getConnection();
              <xsl:if test="esql:allow-multiple-results">
               _esql_connection.setMultipleResults(String.valueOf(<xsl:copy-of 
select="$allow-multiple-results"/>));
              </xsl:if>
            } catch (Exception _esql_exception_<xsl:value-of 
select="generate-id(.)"/>) {
              getLogger().error("Could not get the 
datasource",_esql_exception_<xsl:value-of select="generate-id(.)"/>);
              throw new RuntimeException("Could not get the datasource 
"+_esql_exception_<xsl:value-of select="generate-id(.)"/>);
            }
          </xsl:when>
          <xsl:otherwise>
            <xsl:if test="esql:driver">
            try {
              
Thread.currentThread().getContextClassLoader().loadClass(String.valueOf(<xsl:copy-of
 select="$driver"/>)).newInstance();
            } catch (Exception _esql_exception_<xsl:value-of 
select="generate-id(.)"/>) {
              throw new RuntimeException("Error loading driver: 
"+String.valueOf(<xsl:copy-of select="$driver"/>));
            }
            </xsl:if>
            try {
              _esql_connection.setUrl(String.valueOf(<xsl:copy-of 
select="$dburl"/>));
              <xsl:if test="esql:username">
                _esql_connection.setUser(String.valueOf(<xsl:copy-of 
select="$username"/>));
              </xsl:if>
              <xsl:if test="esql:password">
                _esql_connection.setPassword(String.valueOf(<xsl:copy-of 
select="$password"/>));
              </xsl:if>
              <xsl:for-each select="esql:property">
                _esql_connection.setProperty("<xsl:value-of 
select="@name"/>",<xsl:call-template name="get-nested-string"><xsl:with-param 
name="content" select="."/></xsl:call-template>);
              </xsl:for-each>
              <xsl:if test="esql:allow-multiple-results">
                _esql_connection.setMultipleResults(String.valueOf(<xsl:copy-of 
select="$allow-multiple-results"/>));
              </xsl:if>
              _esql_connection.connection = 
DriverManager.getConnection(_esql_connection.getUrl(), 
_esql_connection.getInfo());
            } catch (Exception _esql_exception_<xsl:value-of 
select="generate-id(.)"/>) {
              throw new RuntimeException("Error opening connection to dburl: 
"+String.valueOf(<xsl:copy-of select="$dburl"/>)+": 
"+_esql_exception_<xsl:value-of select="generate-id(.)"/>.getMessage());
            }
          </xsl:otherwise>
        </xsl:choose>
        try {
          if ("false".equals(String.valueOf(<xsl:copy-of 
select="$autocommit"/>))) {
            if (_esql_connection.getAutoCommit()) {
              _esql_connection.setAutoCommit(false);
            }
          } else {
            if (!_esql_connection.getAutoCommit()) {
              _esql_connection.setAutoCommit(true);
            }
          }
        } catch (Exception _esql_exception_<xsl:value-of 
select="generate-id(.)"/>) {
          // do NOT: throw new RuntimeException("Error setting connection 
autocommit");
        }
        <xsl:if test="esql:use-limit-clause">
          _esql_connection.setLimitMethod(String.valueOf(<xsl:copy-of 
select="$use-limit-clause"/>));
        </xsl:if>
        <xsl:apply-templates/>
      } finally {
        try {
          if(!_esql_connection.getAutoCommit()) {
            _esql_connection.commit();
          }
          _esql_connection.close();
          if (_esql_connections.empty()) {
            _esql_connection = null;
          } else {
            _esql_connection = (EsqlConnectionCocoon2)_esql_connections.pop();
          }
        } catch (Exception _esql_exception_<xsl:value-of 
select="generate-id(.)"/>) {}
      }
    </xsp:logic>
  </xsl:template>
  
  <xsl:template match="esql:connection/esql:driver"/>
  <xsl:template match="esql:connection/esql:dburl"/>
  <xsl:template match="esql:connection/esql:username"/>
  <xsl:template match="esql:connection/esql:password"/>
  <xsl:template match="esql:connection/esql:pool"/>
  <xsl:template match="esql:connection/esql:allow-multiple-results"/>
  <xsl:template match="esql:connection/esql:autocommit"/>
  <xsl:template match="esql:connection/esql:use-limit-clause"/>
  <xsl:template match="esql:connection/esql:property"/>
  
  <xspdoc:desc>Returns the connection's meta data.</xspdoc:desc>
  <xsl:template match="esql:get-connection-metadata">
    <xsp:expr>_esql_connection.getMetaData()</xsp:expr>
  </xsl:template>
  
  <xsl:template match="esql:connection/esql:get-connection">
    <xsp:expr>_esql_connection</xsp:expr>
  </xsl:template>
  
  <!-- set one parameter of a prepared or callable statement and use correct 
method for type -->
  <xsl:template name="set-query-parameter">
    <xsl:choose>
      <xsl:when test="@type">
        <xsl:variable name="type"><xsl:value-of 
select="concat(translate(substring(@type,1,1),'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ'),substring(@type,2))"/></xsl:variable>
        <xsl:text>set</xsl:text><xsl:value-of select="$type"/>(<xsl:value-of 
select="position()"/>,<xsl:call-template 
name="get-nested-content"><xsl:with-param name="content" 
select="."/></xsl:call-template>);<xsl:text>
        </xsl:text>
      </xsl:when>
      <xsl:otherwise>
        <xsl:text>setString(</xsl:text><xsl:value-of 
select="position()"/>,String.valueOf(<xsl:call-template 
name="get-nested-string"><xsl:with-param name="content" 
select="."/></xsl:call-template>));<xsl:text>
        </xsl:text>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
  
  <xspdoc:desc> internal. set one parameter of a callable statement 
</xspdoc:desc>
  <xsl:template name="set-call-parameter">
    <xsl:if test="@direction='out' or @direction='inout'">
      <xsl:text>_esql_query.getCallableStatement().</xsl:text>
      registerOutParameter(<xsl:value-of select="position()"/>, 
<xsl:call-template name="get-Sql-Type"><xsl:with-param 
name="type"><xsl:value-of 
select="@type"/></xsl:with-param></xsl:call-template><xsl:if test="@typename">, 
<xsl:value-of select="@typename"/> </xsl:if>);
    </xsl:if>
    <xsl:if test="not(@direction) or @direction='inout' or @direction='in'">
      <xsl:text>_esql_query.getCallableStatement().</xsl:text>
      <xsl:call-template name="set-query-parameter"/>
    </xsl:if>
  </xsl:template>
  
  
  
  <xspdoc:desc> internal. set one parameter of a prepared statement 
</xspdoc:desc>
  <xsl:template name="set-parameter">
    <xsl:text>_esql_query.getPreparedStatement().</xsl:text>
    <xsl:call-template name="set-query-parameter"/>
  </xsl:template>
  
  <xsl:template name="do-results">
    do {
       if (_esql_query.hasResultSet()) {
          _esql_query.getResultRows();
          if (_esql_query.nextRow()) {
             switch (_esql_query.getResultCount()) {
             <xsl:for-each select="esql:results">
               case <xsl:value-of select="position()"/>: <xsl:if 
test="position()=last()"><xsl:text>
               default: </xsl:text></xsl:if><xsl:apply-templates select="."/>
                   break;
             </xsl:for-each>
             }
          } else {
             switch (_esql_query.getUpdateCountCount()) {
             <xsl:for-each select="esql:no-results">
               case <xsl:value-of select="position()"/>: <xsl:if 
test="position()=last()"><xsl:text>
             default: </xsl:text></xsl:if><xsl:apply-templates select="."/>
                   break;
             </xsl:for-each>
             }
          }
          _esql_query.getResultSet().close();
       } else {
          if (_esql_query.getUpdateCount() &gt; 0) {
             switch (_esql_query.getUpdateCountCount()) {
             <xsl:for-each select="esql:update-results">
               case <xsl:value-of select="position()"/>: <xsl:if 
test="position()=last()"><xsl:text>
               default: </xsl:text></xsl:if><xsl:apply-templates select="."/>
                   break;
             </xsl:for-each>
             }
          } else {
             switch (_esql_query.getUpdateCountCount()) {
             <xsl:for-each select="esql:no-results">
               case <xsl:value-of select="position()"/>: <xsl:if 
test="position()=last()"><xsl:text>
               default: </xsl:text></xsl:if><xsl:apply-templates select="."/>
                   break;
             </xsl:for-each>
             }
          }
       }
     } while(_esql_connection.multipleResults() &amp;&amp; 
_esql_query.getMoreResults());
  </xsl:template>
  
  
  <xsl:template match="esql:connection//esql:execute-query">
  
    <xsl:variable name="query"><xsl:choose><xsl:when 
test="esql:query"><xsl:call-template name="get-nested-string"><xsl:with-param 
name="content" select="esql:query"/></xsl:call-template></xsl:when><xsl:when 
test="esql:call"><xsl:call-template name="get-nested-string"><xsl:with-param 
name="content" 
select="esql:call"/></xsl:call-template></xsl:when></xsl:choose></xsl:variable>
  
    <xsl:variable name="maxrows"><xsl:call-template 
name="get-nested-string"><xsl:with-param name="content" 
select="esql:max-rows"/></xsl:call-template></xsl:variable>
    <xsl:variable name="skiprows"><xsl:call-template 
name="get-nested-string"><xsl:with-param name="content" 
select="esql:skip-rows"/></xsl:call-template></xsl:variable>
    <xsp:logic>
      if (_esql_query != null) {
        _esql_queries.push(_esql_query);
      }
      _esql_query = new EsqlQuery( _esql_connection, 
String.valueOf(<xsl:copy-of select="$query"/>) );
  
      <xsl:if test="esql:max-rows">
        try {
          _esql_query.setMaxRows( Integer.parseInt(String.valueOf(<xsl:copy-of 
select="$maxrows"/>).trim()) );
        } catch (NumberFormatException e) {}
      </xsl:if>
  
      <xsl:if test="esql:skip-rows">
        try {
          _esql_query.setSkipRows( Integer.parseInt(String.valueOf(<xsl:copy-of 
select="$skiprows"/>).trim()) );
        } catch (NumberFormatException e) {}
      </xsl:if>
  
      try {
        <xsl:choose>
          <xsl:when test="esql:call">
              _esql_query.prepareCall();
            <xsl:for-each select="esql:call//esql:parameter">
              <xsl:call-template name="set-call-parameter"/>
            </xsl:for-each>
            <xsl:choose>
              <xsl:when test="esql:[EMAIL PROTECTED]'true' or 
@needs-query='yes']">_esql_query.execute(true);</xsl:when>
              <xsl:when test="esql:[EMAIL 
PROTECTED]">_esql_query.execute(<xsl:copy-of select="esql:[EMAIL 
PROTECTED]"/>);</xsl:when>
              <xsl:otherwise>_esql_query.execute();</xsl:otherwise>
            </xsl:choose>
          </xsl:when>
          <xsl:when test="esql:query//esql:parameter">
              _esql_query.prepareStatement();
            <xsl:for-each select="esql:query//esql:parameter">
              <xsl:call-template name="set-parameter"/>
            </xsl:for-each>
              _esql_query.execute();
          </xsl:when>
          <xsl:otherwise>
            _esql_query.createStatement();
            _esql_query.execute();
          </xsl:otherwise>
        </xsl:choose>
        getLogger().debug("esql query: " + _esql_query.getQueryString());
  
        <xsl:call-template name="do-results"/>
  
        <xsl:if test="esql:call">
          // call results
          <xsp:content>
            <xsl:apply-templates select="esql:call-results"/>
          </xsp:content>
        </xsl:if>
  
        _esql_query.getStatement().close();
  
      } catch (SQLException _esql_exception_<xsl:value-of 
select="generate-id(.)"/>) {
          <xsl:choose>
            <xsl:when test="esql:error-results">
            try {
              _esql_exception = _esql_exception_<xsl:value-of 
select="generate-id(.)"/>;
              _esql_exception_writer = new StringWriter();
              _esql_exception.printStackTrace(new 
PrintWriter(_esql_exception_writer));
              <xsl:apply-templates select="esql:error-results"/>
              if (!_esql_connection.getAutoCommit()) {
                _esql_connection.rollback();
              }
            } catch (Exception _esql_exception_<xsl:value-of 
select="generate-id(.)"/>_2) {}
            </xsl:when>
            <xsl:otherwise>
            try {
              if (!_esql_connection.getAutoCommit()) {
                _esql_connection.rollback();
              }
            } catch (Exception _esql_exception_<xsl:value-of 
select="generate-id(.)"/>_2) {}
            throw new RuntimeException("Error executing statement: " + 
_esql_query.getQueryString() + ": "+_esql_exception_<xsl:value-of 
select="generate-id(.)"/>);
            </xsl:otherwise>
          </xsl:choose>
      }
      if (_esql_queries.empty()) {
        _esql_query = null;
      } else {
        _esql_query = (EsqlQuery)_esql_queries.pop();
      }
    </xsp:logic>
  </xsl:template>
  
  <xsl:template match="esql:query//esql:parameter">"?"</xsl:template>
  <xsl:template match="esql:call//esql:parameter">"?"</xsl:template>
  
  <xsl:template match="esql:execute-query//esql:results//esql:row-count">
    <xsp:expr>_esql_query.rowCount()</xsp:expr>
  </xsl:template>
  
  <xsl:template match="esql:execute-query//esql:results">
    <xsp:content>
      <xsl:apply-templates/>
    </xsp:content>
  </xsl:template>
  
  <xsl:template match="esql:execute-query//esql:call-results">
    <xsp:content>
      <xsl:apply-templates/>
    </xsp:content>
  </xsl:template>
  
  <xsl:template match="esql:execute-query//esql:error-results">
    <xsp:content>
      <xsl:apply-templates/>
    </xsp:content>
  </xsl:template>
  
  <xsl:template match="esql:execute-query//esql:no-results">
    <xsp:content>
      <xsl:apply-templates/>
    </xsp:content>
  </xsl:template>
  
  <xsl:template match="esql:execute-query//esql:update-results">
    <xsp:content>
      <xsl:apply-templates/>
    </xsp:content>
  </xsl:template>
  
  <xsl:template match="esql:update-results//esql:get-update-count">
    <xsp:expr>_esql_query.getUpdateCount()</xsp:expr>
  </xsl:template>
  
  
  <xsl:template match="esql:results//esql:row-results">
    <xsl:variable name="group" select=".//esql:group"/>
    <xsp:logic>
      do {
        <xsp:content>
          <xsl:apply-templates/>
        </xsp:content>
        <xsl:call-template name="nextRow"/>
      } while ( _esql_query.keepGoing() );
  
      if (_esql_query.getSkipRows() > 0 ) {
          <xsl:apply-templates 
select="ancestor::esql:results//esql:previous-results" mode="more"/>
      }
  
      if (_esql_query.nextRow()) {
          <xsl:apply-templates 
select="ancestor::esql:results//esql:more-results" mode="more"/>
      }
    </xsp:logic>
  </xsl:template>
  
  
  
  <xspdoc:desc>Only advance one row if no nested groups exist in this query. 
Ignore nested queries.</xspdoc:desc>
  <xsl:template name="nextRow">
    <xsl:if test="not(.//esql:group) or 
generate-id(.//esql:group)=generate-id(.//esql:execute-query//esql:group)">
      <xsp:logic>
    //checking out early?
      if (_esql_query.getMaxRows() != -1 &amp;&amp; _esql_query.getCurrentRow() 
- _esql_query.getSkipRows() == _esql_query.getMaxRows()) {
        _esql_query.setKeepGoing( false );
      } else {  //if not, advance normally
        _esql_query.setKeepGoing( _esql_query.nextRow() );
      }
      </xsp:logic>
    </xsl:if>
  </xsl:template>
  
  
  
  
  <xsl:template match="esql:results//esql:previous-results"/>
  
  
  <xsl:template match="esql:results//esql:previous-results" mode="more">
    <xsp:content>
      <xsl:apply-templates/>
    </xsp:content>
  </xsl:template>
  
  
  
  
  <xspdoc:desc>Allows header elements around groups of consecutive records with 
identical values in column named by @group-on.  Facilitates a single query with 
joins to be used in lieu of some nested queries.</xspdoc:desc>
  <xsl:template match="esql:group//esql:member">
    <xsp:logic>
      do {
         <xsp:content>
           <xsl:apply-templates/>
         </xsp:content>
         <xsl:call-template name="nextRow"/>
      } while (_esql_query.keepGoing() &amp;&amp; 
!_esql_query.hasGroupingVarChanged());
       </xsp:logic>
  </xsl:template>
  
  
  <xspdoc:desc>Used in conjunction with and nested inside esql:group.  
Formatting for individual records goes within esql:member. Header stuff goes in 
between group and member.</xspdoc:desc>
  <xsl:template match="esql:group">
    <xsl:variable name="group">
      <xsl:call-template name="get-column">
        <xsl:with-param name="name">group-on</xsl:with-param>
      </xsl:call-template>
    </xsl:variable>
  
    <xsp:logic>
      _esql_query.groupLevelPlusPlus();
      if (!_esql_query.groupLevelExists()) {
         _esql_query.setGroupingVar(<xsl:copy-of select="$group"/>);
      }
      <xsp:content>
        <xsl:apply-templates/>
      </xsp:content>
      _esql_query.groupLevelMinusMinus();
    </xsp:logic>
  </xsl:template>
  
  
  <xsl:template match="esql:results//esql:more-results"/>
  
  <xsl:template match="esql:results//esql:more-results" mode="more">
    <xsp:content>
      <xsl:apply-templates/>
    </xsp:content>
  </xsl:template>
  
  <xspdoc:desc>results in a set of elements whose names are the names of the 
columns. the elements each have one text child, whose value is the value of the 
column interpreted as a string. No special formatting is allowed here. If you 
want to mess around with the names of the elements or the value of the text 
field, use the type-specific get methods and write out the result fragment 
yourself.</xspdoc:desc>
  <xsl:template match="esql:row-results//esql:get-columns">
    <xsl:variable name="tagcase"><xsl:value-of 
select="@tag-case"/></xsl:variable>
        <xsp:logic>
          for (int _esql_i = 1; _esql_i &lt;= 
_esql_query.getResultSetMetaData().getColumnCount(); _esql_i++) {
            String _esql_tagname = 
_esql_query.getResultSetMetaData().getColumnName(_esql_i);
            <xsp:element>
              <xsp:param name="name">
                <xsl:choose>
                  <xsl:when test="$tagcase='lower'">
                    <xsp:expr>_esql_tagname.toLowerCase()</xsp:expr>
                  </xsl:when>
                  <xsl:when test="$tagcase='upper'">
                    <xsp:expr>_esql_tagname.toUpperCase()</xsp:expr>
                  </xsl:when>
                  <xsl:otherwise>
                    <xsp:expr>_esql_tagname</xsp:expr>
                  </xsl:otherwise>
                </xsl:choose>
              </xsp:param>
              <xsp:logic>
                
switch(_esql_query.getResultSet().getMetaData().getColumnType(_esql_i)){
                   case java.sql.Types.ARRAY:
                   case java.sql.Types.STRUCT:
                      <xsp:element name="sql-row">
                        <xsp:logic>
                          Object[] _esql_struct = ((Struct) 
_esql_query.getResultSet().getObject(_esql_i)).getAttributes();
                          for ( int _esql_k=0; _esql_k&lt;_esql_struct.length; 
_esql_k++){
                          <xsp:element 
name="sql-row-item"><xsp:logic>this._esql_printObject(_esql_struct[_esql_k],xspAttr);</xsp:logic></xsp:element>
                          }
                        </xsp:logic>
                      </xsp:element>
                      break;
  
                   case java.sql.Types.OTHER: // This is what Informix uses for 
Sets, Bags, Lists
                      // postgres is broken as it doesn't allow getObject()
                      // to retrieve any type (i.e. bit and bit varying)
                      // so don't handle complex types different for postgres
                      if 
(!_esql_connection.getUrl().startsWith("jdbc:postgresql:")) {
                         
this._esql_printObject(_esql_query.getResultSet().getObject(_esql_i), xspAttr);
                         break;
                      }
  
                   default:
                      // standard type
                      <xsp:content>
                      <xsp:expr>
                        <xsl:call-template name="get-string-encoded">
                          <xsl:with-param name="null"><xsl:value-of 
select="@null"/></xsl:with-param>
                          <xsl:with-param 
name="column-spec">_esql_i</xsl:with-param>
                          <xsl:with-param 
name="resultset">_esql_query.getResultSet()</xsl:with-param>
                        </xsl:call-template>
                      </xsp:expr></xsp:content>
                }
              </xsp:logic>
            </xsp:element>
          }
          this.characters("\n");
        </xsp:logic>
  </xsl:template>
  
  <xspdoc:desc>returns the value of the given column as a string</xspdoc:desc>
  <xsl:template 
match="esql:row-results//esql:get-string|esql:call-results//esql:get-string" 
name="get-string">
    <xsp:expr>
      <xsl:call-template name="get-string-encoded">
        <xsl:with-param name="null"><xsl:value-of 
select="@null"/></xsl:with-param>
        <xsl:with-param name="column-spec"><xsl:call-template 
name="get-column"/></xsl:with-param>
        <xsl:with-param name="resultset"><xsl:call-template 
name="get-resultset"/></xsl:with-param>
      </xsl:call-template>
    </xsp:expr>
  </xsl:template>
  
  <xspdoc:desc>returns the value of the given column as a date. if a format 
attribute exists, its value is taken to be a date format string as defined in 
java.text.SimpleDateFormat, and the result is formatted 
accordingly.</xspdoc:desc>
  <xsl:template 
match="esql:row-results//esql:get-date|esql:call-results//esql:get-date">
    <xsl:choose>
      <xsl:when test="@format">
        <xsp:expr><xsl:call-template 
name="get-resultset"/>.getDate(<xsl:call-template name="get-column"/>) == null 
? "" : new SimpleDateFormat("<xsl:value-of 
select="@format"/>").format(<xsl:call-template 
name="get-resultset"/>.getDate(<xsl:call-template 
name="get-column"/>))</xsp:expr>
      </xsl:when>
      <xsl:otherwise>
        <xsp:expr><xsl:call-template 
name="get-resultset"/>.getDate(<xsl:call-template 
name="get-column"/>)</xsp:expr>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
  
  <xspdoc:desc>returns the value of the given column as a time. if a format 
attribute exists, its value is taken to be a date format string as defined in 
java.text.SimpleDateFormat, and the result is formatted 
accordingly.</xspdoc:desc>
  <xsl:template 
match="esql:row-results//esql:get-time|esql:call-results//esql:get-time">
    <xsl:choose>
      <xsl:when test="@format">
        <xsp:expr><xsl:call-template 
name="get-resultset"/>.getTime(<xsl:call-template name="get-column"/>) == null 
? "" : new SimpleDateFormat("<xsl:value-of 
select="@format"/>").format(<xsl:call-template 
name="get-resultset"/>.getTime(<xsl:call-template 
name="get-column"/>))</xsp:expr>
      </xsl:when>
      <xsl:otherwise>
        <xsp:expr><xsl:call-template 
name="get-resultset"/>.getTime(<xsl:call-template 
name="get-column"/>)</xsp:expr>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
  
  <xspdoc:desc>returns the value of the given column as a timestamp. if a 
format attribute exists, its value is taken to be a date format string as 
defined in java.text.SimpleDateFormat, and the result is formatted 
accordingly.</xspdoc:desc>
  <xsl:template 
match="esql:row-results//esql:get-timestamp|esql:call-results//esql:get-timestamp">
    <xsl:choose>
      <xsl:when test="@format">
        <xsp:expr><xsl:call-template 
name="get-resultset"/>.getTimestamp(<xsl:call-template name="get-column"/>) == 
null ? "" : new SimpleDateFormat("<xsl:value-of 
select="@format"/>").format(<xsl:call-template 
name="get-resultset"/>.getTimestamp(<xsl:call-template 
name="get-column"/>))</xsp:expr>
      </xsl:when>
      <xsl:otherwise>
        <xsp:expr><xsl:call-template 
name="get-resultset"/>.getTimestamp(<xsl:call-template 
name="get-column"/>)</xsp:expr>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
  
  <xspdoc:desc>returns the value of the given column as true or 
false</xspdoc:desc>
  <xsl:template 
match="esql:row-results//esql:get-boolean|esql:call-results//esql:get-boolean">
    <xsp:expr><xsl:call-template 
name="get-resultset"/>.getBoolean(<xsl:call-template 
name="get-column"/>)</xsp:expr>
  </xsl:template>
  
  <xspdoc:desc>returns the value of the given column as a double. if a format 
attribute exists, its value is taken to be a decimal format string as defined 
in java.text.DecimalFormat, and the result is formatted 
accordingly.</xspdoc:desc>
  <xsl:template 
match="esql:row-results//esql:get-double|esql:call-results//esql:get-double">
    <xsl:choose>
      <xsl:when test="@format">
        <xsp:expr>new DecimalFormat("<xsl:value-of 
select="@format"/>").format(new Double(<xsl:call-template 
name="get-resultset"/>.getDouble(<xsl:call-template 
name="get-column"/>)))</xsp:expr>
      </xsl:when>
      <xsl:otherwise>
        <xsp:expr><xsl:call-template 
name="get-resultset"/>.getDouble(<xsl:call-template 
name="get-column"/>)</xsp:expr>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
  
  <xspdoc:desc>returns the value of the given column as a float. if a format 
attribute exists, its value is taken to be a decimal format string as defined 
in java.text.DecimalFormat, and the result is formatted 
accordingly.</xspdoc:desc>
  <xsl:template 
match="esql:row-results//esql:get-float|esql:call-results//esql:get-float">
    <xsl:choose>
      <xsl:when test="@format">
        <xsp:expr>new DecimalFormat("<xsl:value-of 
select="@format"/>").format(new Float(<xsl:call-template 
name="get-resultset"/>.getFloat(<xsl:call-template 
name="get-column"/>)))</xsp:expr>
      </xsl:when>
      <xsl:otherwise>
        <xsp:expr><xsl:call-template 
name="get-resultset"/>.getFloat(<xsl:call-template 
name="get-column"/>)</xsp:expr>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
  
  <xspdoc:desc>returns the value of the given column as a BigDecimal. if a 
format attribute exists, its value is taken to be a decimal format string as 
defined in java.text.DecimalFormat, and the result is formatted 
accordingly.</xspdoc:desc>
  <xsl:template 
match="esql:row-results//esql:get-bigdecimal|esql:call-results//esql:get-bigdecimal">
    <xsl:choose>
      <xsl:when test="@format">
        <xsp:expr>new DecimalFormat("<xsl:value-of 
select="@format"/>").format(<xsl:call-template 
name="get-resultset"/>.getBigDecimal(<xsl:call-template 
name="get-column"/>))</xsp:expr>
      </xsl:when>
      <xsl:otherwise>
        <xsp:expr><xsl:call-template 
name="get-resultset"/>.getBigDecimal(<xsl:call-template 
name="get-column"/>)</xsp:expr>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
  
  
  <xspdoc:desc>returns the current result set</xspdoc:desc>
  <xsl:template match="esql:results//esql:get-resultset">
    <xsp:expr><xsl:call-template name="get-resultset"/></xsp:expr>
  </xsl:template>
  
  <xspdoc:desc>returns the value of the given column as an object</xspdoc:desc>
  <xsl:template 
match="esql:row-results//esql:get-object|esql:call-results//esql:get-object">
    <xsp:expr><xsl:call-template 
name="get-resultset"/>.getObject(<xsl:call-template 
name="get-column"/>)</xsp:expr>
  </xsl:template>
  
  <xspdoc:desc>returns the value of the given column as an array</xspdoc:desc>
  <xsl:template 
match="esql:row-results//esql:get-array|esql:call-results//esql:get-array">
    <xsp:expr><xsl:call-template 
name="get-resultset"/>.getArray(<xsl:call-template 
name="get-column"/>)</xsp:expr>
  </xsl:template>
  
  <xspdoc:desc>returns the value of the given column as a struct</xspdoc:desc>
  <xsl:template 
match="esql:row-results//esql:get-struct|esql:call-results//esql:get-struct">
    <xsp:expr>(Struct) <xsl:call-template 
name="get-resultset"/>.getObject(<xsl:call-template 
name="get-column"/>)</xsp:expr>
  </xsl:template>
  
  <xspdoc:desc>returns the value of the given column as an integer</xspdoc:desc>
  <xsl:template 
match="esql:row-results//esql:get-int|esql:call-results//esql:get-int">
    <xsp:expr><xsl:call-template 
name="get-resultset"/>.getInt(<xsl:call-template name="get-column"/>)</xsp:expr>
  </xsl:template>
  
  <xspdoc:desc>returns the value of the given column as a long</xspdoc:desc>
  <xsl:template 
match="esql:row-results//esql:get-long|esql:call-results//esql:get-long">
    <xsp:expr><xsl:call-template 
name="get-resultset"/>.getLong(<xsl:call-template 
name="get-column"/>)</xsp:expr>
  </xsl:template>
  
  <xspdoc:desc>returns the value of the given column as a short</xspdoc:desc>
  <xsl:template 
match="esql:row-results//esql:get-short|esql:call-results//esql:get-short">
    <xsp:expr><xsl:call-template 
name="get-resultset"/>.getShort(<xsl:call-template 
name="get-column"/>)</xsp:expr>
  </xsl:template>
  
  <xspdoc:desc>returns the value of the given column as byte array</xspdoc:desc>
  <xsl:template 
match="esql:row-results//esql:get-blob|esql:call-results//esql:get-blob" 
name="get-blob">
        <xsp:expr>EsqlHelper.getBlob(<xsl:call-template 
name="get-resultset"/>,<xsl:call-template name="get-column"/>)</xsp:expr>
  </xsl:template>
  
  <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: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:template>
  
   <xspdoc:desc>returns the value of the given column interpeted as an xml 
fragment.
   The fragment is parsed by the default xsp parser and the document element is 
returned.
   If a root attribute exists, its value is taken to be the name of an element 
to wrap around the contents of
   the fragment before parsing.</xspdoc:desc>
  <xsl:template 
match="esql:row-results//esql:get-xml|esql:call-results//esql:get-xml">
    <xsl:variable name="content">
      <xsl:choose>
        <xsl:when test="@root">
          <xsl:text>"&lt;</xsl:text>
          <xsl:value-of select="@root"/>
          <xsl:text>&gt;"+</xsl:text>
          <xsl:call-template name="get-string"/>
          <xsl:text>+"&lt;/</xsl:text>
          <xsl:value-of select="@root"/>
          <xsl:text>&gt;"</xsl:text>
        </xsl:when>
        <xsl:otherwise>
          <xsl:call-template name="get-string"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>
        <xsp:logic>
        {
            org.apache.cocoon.components.parser.Parser newParser = null;
  
            try {
                newParser = (org.apache.cocoon.components.parser.Parser) 
this.manager.lookup(org.apache.cocoon.components.parser.Parser.ROLE);
  
                InputSource __is = new InputSource(
                        new StringReader(
                            String.valueOf(<xsl:copy-of select="$content"/>)
                        )
                    );
  
  
                XSPUtil.include(__is, this.contentHandler, newParser);
            } catch (Exception e) {
                getLogger().error("Could not include page", e);
            } finally {
                if (newParser != null) this.manager.release((Component) 
newParser);
            }
        }
        </xsp:logic>
  </xsl:template>
  
  <xspdoc:desc>returns the number of columns in the resultset.</xspdoc:desc>
  <xsl:template match="esql:results//esql:get-column-count">
    <xsp:expr><xsl:call-template 
name="get-resultset"/>.getMetaData().getColumnCount()</xsp:expr>
  </xsl:template>
  
  <xspdoc:desc>returns the metadata of the resultset.</xspdoc:desc>
  <xsl:template match="esql:results//esql:get-metadata">
    <xsp:expr><xsl:call-template name="get-resultset"/>.getMetaData()</xsp:expr>
  </xsl:template>
  
  <xspdoc:desc>returns the position of the current row in the result 
set</xspdoc:desc>
  <xsl:template 
match="esql:row-results//esql:get-row-position|esql:results//esql:get-row-position|esql:call-results//esql:get-row-position">
    <xsp:expr>_esql_query.getCurrentRow()</xsp:expr>
  </xsl:template>
  
  <xspdoc:desc>returns the name of the given column. the column must be 
specified by number, not name.</xspdoc:desc>
  <xsl:template match="esql:results//esql:get-column-name">
    <xsp:expr><xsl:call-template 
name="get-resultset"/>.getMetaData().getColumnName(<xsl:call-template 
name="get-column"/>)</xsp:expr>
  </xsl:template>
  
  <xspdoc:desc>returns the label of the given column. the column must be 
specified by number, not name.</xspdoc:desc>
  <xsl:template match="esql:results//esql:get-column-label">
    <xsp:expr><xsl:call-template 
name="get-resultset"/>.getMetaData().getColumnLabel(<xsl:call-template 
name="get-column"/>)</xsp:expr>
  </xsl:template>
  
  <xspdoc:desc>returns the name of the type of the given column. the column 
must be specified by number, not name.</xspdoc:desc>
  <xsl:template match="esql:results//esql:get-column-type-name">
    <xsp:expr><xsl:call-template 
name="get-resultset"/>.getMetaData().getColumnTypeName(<xsl:call-template 
name="get-column"/>)</xsp:expr>
  </xsl:template>
  
  <xspdoc:desc>returns the type of the given column as int. the column must be 
specified by number, not name.</xspdoc:desc>
  <xsl:template match="esql:row-results//esql:get-column-type" 
name="get-column-type">
    <xsp:expr><xsl:call-template 
name="get-resultset"/>.getMetaData().getColumnType(<xsl:call-template 
name="get-column"/>)</xsp:expr>
  </xsl:template>
  
  <xspdoc:desc>allows null-column testing. Evaluates to a Java expression, 
which is true when the referred column contains a null-value for the current 
resultset row</xspdoc:desc>
  <xsl:template match="esql:row-results//esql:is-null">
    <xsp:expr>((<xsl:call-template 
name="get-resultset"/>.getObject(<xsl:call-template name="get-column"/>) == 
null) || <xsl:call-template name="get-resultset"/>.wasNull())</xsp:expr>
  </xsl:template>
  
  <xsl:template match="esql:result"/>
  
  <xspdoc:desc>creates a nested query like block that uses the result set 
obtained from a column as current result set. This version is deprecated, 
please use &lt;esql:use-result&gt; instead.</xspdoc:desc>
  <xsl:template 
match="esql:row-results//esql:results[child::esql:result]|esql:call-results//esql:results[child::esql:result]">
    <xsl:call-template name="use-results"/>
  </xsl:template>
  
  <xspdoc:desc>creates a nested query like block that uses the result set 
obtained from a column as current result set.</xspdoc:desc>
  <xsl:template name="use-results" match="esql:use-results[child::esql:result]">
    <xsl:variable name="maxrows"><xsl:call-template 
name="get-nested-string"><xsl:with-param name="content" 
select="esql:max-rows"/></xsl:call-template></xsl:variable>
    <xsl:variable name="skiprows"><xsl:call-template 
name="get-nested-string"><xsl:with-param name="content" 
select="esql:skip-rows"/></xsl:call-template></xsl:variable>
  <xsp:logic>
    // nested result set
      if (_esql_query != null) {
        _esql_queries.push(_esql_query);
      }
      _esql_query = new EsqlQuery((ResultSet) <xsl:apply-templates 
select="esql:result/*"/>);
  
      <xsl:if test="esql:max-rows">
        try {
          _esql_query.setMaxRows( Integer.parseInt(String.valueOf(<xsl:copy-of 
select="$maxrows"/>).trim()) );
        } catch (NumberFormatException e) {}
      </xsl:if>
  
      <xsl:if test="esql:skip-rows">
        try {
          _esql_query.setSkipRows( Integer.parseInt(String.valueOf(<xsl:copy-of 
select="$skiprows"/>).trim()) );
        } catch (NumberFormatException e) {}
      </xsl:if>
  
     {
         <xsl:call-template name="do-results"/>
      }
      if (_esql_queries.empty()) {
        _esql_query = null;
      } else {
        _esql_query = (EsqlQuery)_esql_queries.pop();
      }
    </xsp:logic>
  </xsl:template>
  
  <xspdoc:desc>returns the message of the current exception</xspdoc:desc>
  <xsl:template match="esql:error-results//esql:get-message">
    <xsp:expr>_esql_exception.getMessage()</xsp:expr>
  </xsl:template>
  
  <xspdoc:desc>returns the current exception as a string</xspdoc:desc>
  <xsl:template match="esql:error-results//esql:to-string">
    <xsp:expr>_esql_exception.toString()</xsp:expr>
  </xsl:template>
  
  <xspdoc:desc>returns the stacktrace of the current exception</xspdoc:desc>
  <xsl:template match="esql:error-results//esql:get-stacktrace">
    <xsp:expr>_esql_exception_writer.toString()</xsp:expr>
  </xsl:template>
  
  <xsl:template name="get-resultset">
    <xsl:call-template name="get-query"/><xsl:choose><xsl:when 
test="@from-call='yes' or 
@from-call='true'"><xsl:text>.getCallableStatement()</xsl:text></xsl:when><xsl:otherwise><xsl:text>.getResultSet()</xsl:text></xsl:otherwise></xsl:choose>
  </xsl:template>
  
  <xsl:template name="get-query">
    <xsl:choose>
      <xsl:when test="@ancestor">
        
<xsl:text>((EsqlQuery)_esql_queries.elementAt(_esql_queries.size()-</xsl:text>
        <xsl:value-of select="@ancestor"/>
        <xsl:text>))</xsl:text>
      </xsl:when>
      <xsl:otherwise>
        <xsl:text>_esql_query</xsl:text>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
  
  <xspdoc:desc>used internally to determine which column is the given column. 
if a column attribute exists and its value is a number, it is taken to be the 
column's position. if the value is not a number, it is taken to be the column's 
name. if a column attribute does not exist, an esql:column element is assumed 
to exist and to render as a string (after all of the xsp instructions have been 
evaluated), which is taken to be the column's name.</xspdoc:desc>
  <xsl:template name="get-column">
    <xsl:param name="name">column</xsl:param>
    <xsl:variable name="column">
       <xsl:call-template name="get-parameter">
         <xsl:with-param name="name"><xsl:value-of 
select="$name"/></xsl:with-param>
         <xsl:with-param name="required">true</xsl:with-param>
       </xsl:call-template>
    </xsl:variable>
    <xsl:choose>
      <xsl:when test="starts-with($column,'&quot;')">
        <xsl:variable name="raw-column">
          <xsl:value-of select="substring($column,2,string-length($column)-2)"/>
        </xsl:variable>
        <xsl:choose>
          <xsl:when test="not(string(number($raw-column))='NaN')">
            <xsl:value-of select="$raw-column"/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:value-of select="$column"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:when>
      <xsl:otherwise>
        <xsl:copy-of select="$column"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
  
  <xsl:template name="get-string-encoded">
    <xsl:param name="column-spec"/>
    <xsl:param name="resultset"/>
    <xsl:param name="null"/>
    <xsl:variable name="encoding">
      <xsl:choose>
        <xsl:when test="@encoding">"<xsl:value-of 
select="@encoding"/>"</xsl:when>
        <xsl:when test="esql:encoding">
          <xsl:call-template name="get-nested-string">
            <xsl:with-param name="content" select="esql:encoding"/>
          </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>default</xsl:otherwise>
      </xsl:choose>
    </xsl:variable>
    <xsl:choose>
      <xsl:when test="$encoding = 'default'">
        EsqlHelper.getAscii(<xsl:value-of select="$resultset"/>,<xsl:value-of 
select="$column-spec"/>)
      </xsl:when>
      <xsl:otherwise>
        EsqlHelper.getStringFromByteArray(<xsl:value-of 
select="$resultset"/>.getBytes
          (<xsl:value-of select="$column-spec"/>), <xsl:value-of 
select="$encoding"/>)
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
  
  <xsl:template name="get-Sql-Type">
    <xsl:param name="type"/>
    <xsl:choose>
      <!-- just do the 'unusual' mappings -->
      <xsl:when test="$type='Byte'">Types.TINYINT</xsl:when>
      <xsl:when test="$type='Short'">Types.SMALLINT</xsl:when>
      <xsl:when test="$type='Int'">Types.INTEGER</xsl:when>
      <xsl:when test="$type='Long'">Types.BIGINT</xsl:when>
      <xsl:when test="$type='Float'">Types.REAL</xsl:when>
      <xsl:when test="$type='BigDecimal'">Types.DECIMAL</xsl:when>
      <xsl:when test="$type='Boolean'">Types.BIT</xsl:when>
      <xsl:when test="$type='String'">Types.VARCHAR</xsl:when>
      <xsl:when test="$type='Bytes'">Types.BINARY</xsl:when>
      <xsl:when test="$type='AsciiStream'">Types.LONGVARCHAR</xsl:when>
      <xsl:when test="$type='UnicodeStream'">Types.LONGVARCHAR</xsl:when>
      <xsl:when test="$type='BinaryStream'">Types.VARBINARY</xsl:when>
      <!-- handle DBMS specific types e.g. 
oracle.jdbc.driver.OracleTypes.CURSOR -->
      <xsl:when test="contains($type,'.')"><xsl:value-of 
select="$type"/></xsl:when>
      <!-- default to upper case type -->
      <xsl:otherwise>Types.<xsl:value-of 
select="translate(@type,'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/></xsl:otherwise>
    </xsl:choose>
  </xsl:template>
  
  <!--
    Break on error.
    @param message explanation of the error
  -->
  <xsl:template name="error">
    <xsl:param name="message"/>
    <xsl:message terminate="yes"><xsl:value-of select="$message"/></xsl:message>
  </xsl:template>
  
  <!--
       swallow esql:param tags
  -->
  <xsl:template match="esql:param"/>
  
  
  <xsl:template match="@*|node()" priority="-1">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>
  
  </xsl:stylesheet>
  
  
  
  1.1                  
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/acting/AbstractDatabaseAction.java
  
  Index: AbstractDatabaseAction.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
      [EMAIL PROTECTED]
  
   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  <[EMAIL PROTECTED]>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  package org.apache.cocoon.acting;
  
  import org.apache.avalon.excalibur.datasource.DataSourceComponent;
  import org.apache.avalon.framework.activity.Disposable;
  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.configuration.Configurable;
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.parameters.Parameters;
  import org.apache.cocoon.environment.Request;
  import org.apache.cocoon.generation.ImageDirectoryGenerator;
  
  import java.io.*;
  import java.math.BigDecimal;
  import java.sql.*;
  import java.text.DateFormat;
  import java.text.SimpleDateFormat;
  import java.util.Collections;
  import java.util.HashMap;
  import java.util.Map;
  
  /**
   * Set up environment for configurable form handling data.  It is
   * important to note that all DatabaseActions use a common configuration
   * format.  This group of actions are unique in that they employ a
   * terciary mapping.  There is the Form parameter, the database column,
   * and the type.
   *
   * Each configuration file must use the same format in order to be
   * effective.  The name of the root configuration element is irrelevant.
   *
   * <pre>
   *   &lt;root&gt;
   *     &lt;connection&gt;personnel&lt;connection&gt;
   *     &lt;table&gt;
   *       &lt;keys&gt;
   *         &lt;key param="id" dbcol="id" type="int"/&gt;
   *       &lt;/keys&gt;
   *       &lt;values&gt;
   *         &lt;value param="name" dbcol="name" type="string"/&gt;
   *         &lt;value param="department" dbcol="department_id" type="int"/&gt;
   *       &lt;/values&gt;
   *     &lt;/table&gt;
   *   &lt;/root&gt;
   * </pre>
   *
   * The types recognized by this system are:
   *
   * <table>
   *   <tr>
   *     <th>Type</th>
   *     <th>Description</th>
   *   </tr>
   *   <tr>
   *     <td>ascii</td>
   *     <td>ASCII Input Stream, a CLOB input</td>
   *   </tr>
   *   <tr>
   *     <td>big-decimal</td>
   *     <td>a <code>java.math.BigDecimal</code> value</td>
   *   </tr>
   *   <tr>
   *     <td>binary</td>
   *     <td>Binary Input Stream, a BLOB input</td>
   *   </tr>
   *   <tr>
   *     <td>byte</td>
   *     <td>a Byte</td>
   *   </tr>
   *   <tr>
   *     <td>string</td>
   *     <td>a String</td>
   *   </tr>
   *   <tr>
   *     <td>date</td>
   *     <td>a Date</td>
   *   </tr>
   *   <tr>
   *     <td>double</td>
   *     <td>a Double</td>
   *   </tr>
   *   <tr>
   *     <td>float</td>
   *     <td>a Float</td>
   *   </tr>
   *   <tr>
   *     <td>int</td>
   *     <td>an Integer</td>
   *   </tr>
   *   <tr>
   *     <td>long</td>
   *     <td>a Long</td>
   *   </tr>
   *   <tr>
   *     <td>short</td>
   *     <td>a Short</td>
   *   </tr>
   *   <tr>
   *     <td>time</td>
   *     <td>a Time</td>
   *   </tr>
   *   <tr>
   *     <td>time-stamp</td>
   *     <td>a Timestamp</td>
   *   </tr>
   *   <tr>
   *     <td>now</td>
   *     <td>a Timestamp with the current day/time--the form value is 
ignored.</td>
   *   </tr>
   *   <tr>
   *     <td>image</td>
   *     <td>a binary image file, we cache the attribute information</td>
   *   </tr>
   *   <tr>
   *     <td>image-width</td>
   *     <td>
   *       the width attribute of the cached file attribute.  NOTE:
   *       param attribute must equal the param for image with a
   *       "-width" suffix.
   *     </td>
   *   </tr>
   *   <tr>
   *     <td>image-height</td>
   *     <td>
   *     the width attribute of the cached file attribute  NOTE:
   *       param attribute must equal the param for image with a
   *       "-height" suffix.
   *     </td>
   *   </tr>
   *   <tr>
   *     <td>image-size</td>
   *     <td>
   *       the size attribute of the cached file attribute  NOTE:
   *       param attribute must equal the param for image with a
   *       "-size" suffix.
   *     </td>
   *   </tr>
   * </table>
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Berin Loritsch</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Donald Ball</a>
   * @version CVS $Id: AbstractDatabaseAction.java,v 1.1 2002/10/18 14:04:27 
haul Exp $
   */
  public abstract class AbstractDatabaseAction extends 
AbstractComplementaryConfigurableAction implements Configurable, Disposable {
      protected Map files = new HashMap();
      protected static final Map typeConstants;
      protected ComponentSelector dbselector;
  
      static {
          /** Initialize the map of type names to jdbc column types.
              Note that INTEGER, BLOB, and VARCHAR column types map to more than
              one type name. **/
          Map constants = new HashMap();
          constants.put("ascii", new Integer(Types.CLOB));
          constants.put("big-decimal", new Integer(Types.BIGINT));
          constants.put("binary", new Integer(Types.BLOB));
          constants.put("byte", new Integer(Types.TINYINT));
          constants.put("string", new Integer(Types.VARCHAR));
          constants.put("date", new Integer(Types.DATE));
          constants.put("double", new Integer(Types.DOUBLE));
          constants.put("float", new Integer(Types.FLOAT));
          constants.put("int", new Integer(Types.INTEGER));
          constants.put("long", new Integer(Types.NUMERIC));
          constants.put("short", new Integer(Types.SMALLINT));
          constants.put("time", new Integer(Types.TIME));
          constants.put("time-stamp", new Integer(Types.TIMESTAMP));
          constants.put("now", new Integer(Types.LONGVARBINARY));
          //constants.put("image", new Integer(Types.DISTINCT));
          //constants.put("image-width", new Integer(Types.ARRAY));
          //constants.put("image-height", new Integer(Types.BIT));
          //constants.put("image-size", new Integer(Types.CHAR));
          constants.put("image",new Integer(Types.BLOB));
          constants.put("image-width",new Integer(Types.INTEGER));
          constants.put("image-height",new Integer(Types.INTEGER));
          constants.put("image-size",new Integer(Types.INTEGER));
          constants.put("row-index",new Integer(Types.INTEGER));
          constants.put("image-mime-type",new Integer(Types.VARCHAR));
          constants.put("array", new Integer(Types.ARRAY));
          constants.put("row", new Integer(Types.STRUCT));
          constants.put("object", new Integer(Types.OTHER));
          typeConstants = Collections.unmodifiableMap(constants);
      }
  
      /**
       * Compose the Actions so that we can select our databases.
       */
      public void compose(ComponentManager manager) throws ComponentException {
          this.dbselector = (ComponentSelector) 
manager.lookup(DataSourceComponent.ROLE + "Selector");
  
          super.compose(manager);
      }
      /**
       * Get the Datasource we need.
       */
      protected final DataSourceComponent getDataSource(Configuration conf) 
throws ComponentException {
          Configuration dsn = conf.getChild("connection");
  
          return (DataSourceComponent) this.dbselector.select(dsn.getValue(""));
      }
  
      /**
       * Return whether a type is a Large Object (BLOB/CLOB).
       */
      protected final boolean isLargeObject (String type) {
          if ("ascii".equals(type)) return true;
          if ("binary".equals(type)) return true;
          if ("image".equals(type)) return true;
  
          return false;
      }
  
      /**
       * Get the Statement column so that the results are mapped correctly.
       */
      protected Object getColumn(ResultSet set, Request request, Configuration 
entry)
      throws Exception {
          Integer type = (Integer) 
AbstractDatabaseAction.typeConstants.get(entry.getAttribute("type"));
          String attribute = entry.getAttribute("param", "");
          String dbcol = entry.getAttribute("dbcol", "");
          Object value = null;
  
          switch (type.intValue()) {
              case Types.CLOB:
                  Clob dbClob = set.getClob(dbcol);
                  int length = (int) dbClob.length();
                  InputStream asciiStream = new 
BufferedInputStream(dbClob.getAsciiStream());
                  byte[] buffer = new byte[length];
                  asciiStream.read(buffer);
                  String str = new String(buffer);
                  asciiStream.close();
                  value = str;
                  break;
              case Types.BIGINT:
                  value = set.getBigDecimal(dbcol);
                  break;
              case Types.TINYINT:
                  value = new Byte(set.getByte(dbcol));
                  break;
              case Types.VARCHAR:
                  value  = set.getString(dbcol);
                  break;
              case Types.DATE:
                  value = set.getDate(dbcol);
                  break;
              case Types.DOUBLE:
                  value = new Double(set.getDouble(dbcol));
                  break;
              case Types.FLOAT:
                  value = new Float(set.getFloat(dbcol));
                  break;
              case Types.INTEGER:
                  value = new Integer(set.getInt(dbcol));
                  break;
              case Types.NUMERIC:
                  value = new Long(set.getLong(dbcol));
                  break;
              case Types.SMALLINT:
                  value = new Short(set.getShort(dbcol));
                  break;
              case Types.TIME:
                  value = set.getTime(dbcol);
                  break;
              case Types.TIMESTAMP:
                  value = set.getTimestamp(dbcol);
                  break;
              case Types.ARRAY:
                  value = set.getArray(dbcol);
                  break;
              case Types.BIT:
                  value = new Integer(set.getInt(dbcol));
                  break;
              case Types.CHAR:
                  value = new Integer(set.getInt(dbcol));
                  break;
          case Types.STRUCT:
          value = (Struct) set.getObject(dbcol);
          break;
          case Types.OTHER:
          value = set.getObject(dbcol);
          break;
  
              default:
                  // The blob types have to be requested separately, via a 
Reader.
                  value = "";
                  break;
          }
  
          setRequestAttribute(request,attribute,value);
  
          return value;
      }
  
      /**
       * Set the Statement column so that the results are mapped correctly.
       * The name of the parameter is retrieved from the configuration object.
       *
       * @param statement the prepared statement
       * @param position the position of the column
       * @param request the request
       * @param entry the configuration object
       */
      protected void setColumn(PreparedStatement statement, int position, 
Request request, Configuration entry)
      throws Exception {
          
setColumn(statement,position,request,entry,entry.getAttribute("param",""));
      }
  
      /**
       * Set the Statement column so that the results are mapped correctly. The
       * value of the column is retrieved from the request object. If the
       * named parameter exists in the request object's parameters, that value
       * is used. Otherwise if the named parameter exists in the request 
object's
       * attributes, that value is used. Otherwise the request object is
       * retrieved using Request.get(attribute), which is documented to be the
       * same as Request.getAttribute(attribute), so something weird must be
       * going on.
       *
       * @param statement the prepared statement
       * @param position the position of the column
       * @param request the request
       * @param entry the configuration object
       * @param param the name of the request parameter
       */
      protected void setColumn(PreparedStatement statement, int position, 
Request request, Configuration entry, String param)
      throws Exception {
          Object value = request.getParameter(param);
          if (value == null) value = request.getAttribute(param);
          if (value == null) value = request.get(param);
          setColumn(statement,position,request,entry,param,value);
      }
  
      /**
       * Set the Statement column so that the results are mapped correctly.
       *
       * @param statement the prepared statement
       * @param position the position of the column
       * @param request the request
       * @param entry the configuration object
       * @param param the name of the request parameter
       * @param value the value of the column
       */
      protected void setColumn(PreparedStatement statement, int position, 
Request request, Configuration entry, String param, Object value) throws 
Exception {
          setColumn(statement,position,request,entry,param,value,0);
      }
  
      /**
       * Set the Statement column so that the results are mapped correctly.
       *
       * @param statement the prepared statement
       * @param position the position of the column
       * @param request the request
       * @param entry the configuration object
       * @param param the name of the request parameter
       * @param value the value of the column
       * @param rowIndex the index of the current row for manyrows inserts
       */
      protected void setColumn(PreparedStatement statement, int position, 
Request request, Configuration entry, String param, Object value, int rowIndex) 
throws Exception {
          getLogger().debug("Setting column "+position+" named "+param+" with 
value "+value);
          if (value instanceof String) {
              value = ((String) value).trim();
          }
          String typeName = entry.getAttribute("type");
          Integer typeObject = (Integer) 
AbstractDatabaseAction.typeConstants.get(typeName);
          if (typeObject == null) {
              throw new SQLException("Can't set column because the type 
"+typeName+" is unrecognized");
          }
          if (value == null) {
              /** If the value is null, set the column value null and return **/
              if (typeName.equals("image-width") || 
typeName.equals("image-height") || typeName.equals("image-size") || 
typeName.equals("row-index") || typeName.equals("image-mime-type")) {
                /** these column types are automatically generated so it's ok 
**/
              } else {
                statement.setNull(position, typeObject.intValue());
                return;
              }
          }
          if ("".equals(value)) {
              switch (typeObject.intValue()) {
                  case Types.CHAR:
                  case Types.CLOB:
                  case Types.VARCHAR:
                      /** If the value is an empty string and the column is
                          a string type, we can continue **/
                      break;
                  case Types.INTEGER:
                    if (typeName.equals("image-width") || 
typeName.equals("image-height") || typeName.equals("image-size") || 
typeName.equals("row-index")) {
                      /** again, these types are okay to be absent **/
                      break;
                    }
                  default:
                      /** If the value is an empty string and the column
                          is something else, we treat it as a null value **/
                      statement.setNull(position, typeObject.intValue());
                      return;
              }
          }
  
          /** Store the column value in the request attribute
              keyed by the request parameter name. we do this so possible future
              actions can access this data. not sure about the key tho... **/
          setRequestAttribute(request,param,value);
          File file;
  
          switch (typeObject.intValue()) {
              case Types.CLOB:
                  int length = -1;
                  InputStream asciiStream = null;
  
                  if (value instanceof File) {
                      File asciiFile = (File) value;
                      asciiStream = new BufferedInputStream(new 
FileInputStream(asciiFile));
                      length = (int) asciiFile.length();
                  } else {
                      String asciiText = (String) value;
                      asciiStream = new BufferedInputStream(new 
ByteArrayInputStream(asciiText.getBytes()));
                      length = asciiText.length();
                  }
  
                  statement.setAsciiStream(position, asciiStream, length);
                  break;
              case Types.BIGINT:
                  BigDecimal bd = null;
  
                  if (value instanceof BigDecimal) {
                      bd = (BigDecimal) value;
                  } else {
                      bd = new BigDecimal((String) value);
                  }
  
                  statement.setBigDecimal(position, bd);
                  break;
              case Types.TINYINT:
                  Byte b = null;
  
                  if (value instanceof Byte) {
                      b = (Byte) value;
                  } else {
                      b = new Byte((String) value);
                  }
  
                  statement.setByte(position, b.byteValue());
                  break;
              case Types.DATE:
                  Date d = null;
  
                  if (value instanceof Date) {
                      d = (Date) value;
                  } else if (value instanceof java.util.Date) {
                      d = new Date(((java.util.Date) value).getTime());
                  } else {
                      d = new Date(this.dateValue((String) value, 
entry.getAttribute("format", "M/d/yyyy")));
                  }
  
                  statement.setDate(position, d);
                  break;
              case Types.DOUBLE:
                  Double db = null;
  
                  if (value instanceof Double) {
                      db = (Double) value;
                  } else {
                      db = new Double((String) value);
                  }
  
                  statement.setDouble(position, db.doubleValue());
                  break;
              case Types.FLOAT:
                  Float f = null;
  
                  if (value instanceof Float) {
                      f = (Float) value;
                  } else {
                      f = new Float((String) value);
                  }
  
                  statement.setFloat(position, f.floatValue());
                  break;
              case Types.NUMERIC:
                  Long l = null;
  
                  if (value instanceof Long) {
                      l = (Long) value;
                  } else {
                      l = new Long((String) value);
                  }
  
                  statement.setLong(position, l.longValue());
                  break;
              case Types.SMALLINT:
                  Short s = null;
  
                  if (value instanceof Short) {
                      s = (Short) value;
                  } else {
                      s = new Short((String) value);
                  }
  
                  statement.setShort(position, s.shortValue());
                  break;
              case Types.TIME:
                  Time t = null;
  
                  if (value instanceof Time) {
                      t = (Time) value;
                  } else {
                      t = new Time(this.dateValue((String) value, 
entry.getAttribute("format", "h:m:s a")));
                  }
  
                  statement.setTime(position, t);
                  break;
              case Types.TIMESTAMP:
                  Timestamp ts = null;
  
                  if (value instanceof Time) {
                      ts = (Timestamp) value;
                  } else {
                      ts = new Timestamp(this.dateValue((String) value, 
entry.getAttribute("format", "M/d/yyyy h:m:s a")));
                  }
  
                  statement.setTimestamp(position, ts);
                  break;
              case Types.ARRAY:
                  statement.setArray(position, (Array) value); // no way to 
convert string to array
                  break;
              case Types.STRUCT:
              case Types.OTHER:
                  statement.setObject(position, value);
                  break;
              case Types.LONGVARBINARY:
                  statement.setTimestamp(position, new Timestamp((new 
java.util.Date()).getTime()));
                  break;
              case Types.VARCHAR:
                  if ("string".equals(typeName)) {
                     statement.setString(position, (String) value);
                     break;
                  } else if ("image-mime-type".equals(typeName)) {
                      String imageAttr = param.substring(0, (param.length() - 
"-mime-type".length()));
                      file = (File) request.get(imageAttr);
                      synchronized (this.files) {
                          Parameters parameters = (Parameters) 
this.files.get(file);
                          String imageMimeType = 
parameters.getParameter("image-mime-type",
                                                                         
(String) settings.get("image-mime-type",""));
                          statement.setString(position, imageMimeType);
                          /** Store the image mime type in the request 
attributes.
                              Why do we do this? **/
                          setRequestAttribute(request, param, imageMimeType);
                      }
                      break;
                  }
              case Types.BLOB:
                  if (value instanceof File) {
                      file = (File)value;
                  } else if (value instanceof String) {
                      file = new File((String)value);
                  } else {
                      throw new SQLException("Invalid type for blob: 
"+value.getClass().getName());
                  }
                  //InputStream input = new BufferedInputStream(new 
FileInputStream(file));
                  FileInputStream input = new FileInputStream(file);
                  statement.setBinaryStream(position, input, 
(int)file.length());
                  if ("image".equals(typeName)) {
                      /** If this column type is an image, store the
                          size, width, and height in a static table **/
                      Parameters parameters = new Parameters();
                      parameters.setParameter("image-size", 
Long.toString(file.length()));
                      int [] dimensions = ImageDirectoryGenerator.getSize(file);
                      String type = ImageDirectoryGenerator.getFileType(file);
                      parameters.setParameter("image-width", 
Integer.toString(dimensions[0]));
                      parameters.setParameter("image-height", 
Integer.toString(dimensions[1]));
                      parameters.setParameter("image-mime-type",type);
                      synchronized (this.files) {
                          this.files.put(file, parameters);
                      }
                  }
                  break;
              case Types.INTEGER:
                  if ("int".equals(typeName)) {
                      Integer i = null;
                      if (value instanceof Integer) {
                          i = (Integer) value;
                      } else {
                          i = new Integer((String) value);
                      }
                      statement.setInt(position, i.intValue());
                      break;
                  } else if ("image-width".equals(typeName)) {
                      /** Get the image width from the cached image data **/
                      /** Is this why we store the values in the request
                          attributes? **/
                      String imageAttr = param.substring(0, (param.length() - 
"-width".length()));
                      file = (File) request.get(imageAttr);
                      synchronized (this.files) {
                          Parameters parameters = (Parameters) 
this.files.get(file);
                          statement.setInt(position, 
parameters.getParameterAsInteger("image-width",
                           
Integer.parseInt((String)settings.get("image-width","-1"))));
                          /** Store the image width in the request attributes.
                              Why do we do this? **/
                          setRequestAttribute(request,
                          param,
                          parameters.getParameter("image-width",
                                      (String) settings.get("image-width","")));
                      }
                      break;
                  } else if ("image-height".equals(typeName)) {
                      /** Get the image height from the cached image data **/
                      String imageAttr = param.substring(0, (param.length() - 
"-height".length()));
                      file = (File) request.get(imageAttr);
                      synchronized (this.files) {
                          Parameters parameters = (Parameters) 
this.files.get(file);
                          statement.setInt(position, 
parameters.getParameterAsInteger("image-height",
                           
Integer.parseInt((String)settings.get("image-height","-1"))));
                          setRequestAttribute(request,
                          param,
                          parameters.getParameter("image-height",
                                      (String) 
settings.get("image-height","")));
                      }
                      break;
                  } else if ("image-size".equals(typeName)) {
                      /** Get the image file size from the cached image data **/
                      String imageAttr = param.substring(0, (param.length() - 
"-size".length()));
                      file = (File) request.get(imageAttr);
                      synchronized (this.files) {
                          Parameters parameters = (Parameters) 
this.files.get(file);
                          statement.setInt(position, 
parameters.getParameterAsInteger("image-size",
                           
Integer.parseInt((String)settings.get("image-height","-1"))));
                          setRequestAttribute(request,
                          param,
                          parameters.getParameter("image-size",
                                      (String) settings.get("image-size","")));
                      }
                      break;
                  } else if ("row-index".equals(typeName)) {
                      statement.setInt(position,rowIndex);
                      break;
                  }
              default:
                  throw new SQLException("Impossible exception - invalid type 
"+typeName);
          }
      }
  
      /**
       * Convert a String to a long value.
       */
      private final long dateValue(String value, String format) throws 
Exception {
          DateFormat formatter = new SimpleDateFormat(format);
          return formatter.parse(value).getTime();
      }
  
      /**
       *  dispose
       */
      public void dispose() {
          this.manager.release(dbselector);
      }
  
      /**
       * Store a key/value pair in the request attributes. We prefix the key
       * with the name of this class to prevent potential name collisions.
       */
      protected void setRequestAttribute(Request request, String key, Object 
value) {
        
request.setAttribute("org.apache.cocoon.acting.AbstractDatabaseAction:"+key,value);
      }
  
      /**
       * Retreive a value from the request attributes.
       */
      protected Object getRequestAttribute(Request request, String key) {
        return 
request.getAttribute("org.apache.cocoon.acting.AbstractDatabaseAction:"+key);
      }
  
  }
  
  
  
  1.1                  
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/acting/DatabaseAddAction.java
  
  Index: DatabaseAddAction.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
      [EMAIL PROTECTED]
  
   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  <[EMAIL PROTECTED]>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  package org.apache.cocoon.acting;
  
  import org.apache.avalon.excalibur.datasource.DataSourceComponent;
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.configuration.ConfigurationException;
  import org.apache.avalon.framework.parameters.Parameters;
  import org.apache.avalon.framework.thread.ThreadSafe;
  import org.apache.cocoon.Constants;
  import org.apache.cocoon.ProcessingException;
  import org.apache.cocoon.environment.ObjectModelHelper;
  import org.apache.cocoon.environment.Redirector;
  import org.apache.cocoon.environment.Request;
  import org.apache.cocoon.environment.SourceResolver;
  
  import java.sql.Connection;
  import java.sql.PreparedStatement;
  import java.sql.ResultSet;
  import java.sql.SQLException;
  import java.util.*;
  
  /**
   * Adds record in a database. The action can update one or more tables,
   * and can add more than one row to a table at a time. The form descriptor
   * semantics for this are still in a bit of a state of flux. Note
   * that if a secondary table relies on the value of a new primary key in a
   * primary table, the primary key must be created using manual mode.
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Berin Loritsch</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Donald Ball</a>
   * @version CVS $Id: DatabaseAddAction.java,v 1.1 2002/10/18 14:04:27 haul 
Exp $
   */
  public class DatabaseAddAction extends AbstractDatabaseAction implements 
ThreadSafe {
      protected static final Map addStatements = new HashMap();
      private static final Map selectStatements = new HashMap();
  
      /**
       * Add a record to the database.  This action assumes that
       * the file referenced by the "descriptor" parameter conforms
       * to the AbstractDatabaseAction specifications.
       */
      public Map act(Redirector redirector, SourceResolver resolver, Map 
objectModel, String source, Parameters param) throws Exception {
          DataSourceComponent datasource = null;
          Connection conn = null;
          Map results = new HashMap();
  
          // read global parameter settings
          boolean reloadable = Constants.DESCRIPTOR_RELOADABLE_DEFAULT;
          if (this.settings.containsKey("reloadable"))
              reloadable = Boolean.valueOf((String) 
this.settings.get("reloadable")).booleanValue();
          // read local parameter settings
          try {
              Configuration conf =
                  this.getConfiguration(param.getParameter("descriptor", 
(String) this.settings.get("descriptor")), resolver,
                                        
param.getParameterAsBoolean("reloadable",reloadable));
  
              datasource = this.getDataSource(conf);
              conn = datasource.getConnection();
              Request request = ObjectModelHelper.getRequest(objectModel);
  
              if (conn.getAutoCommit()) {
                  conn.setAutoCommit(false);
              }
  
              Configuration[] tables = conf.getChildren("table");
              for (int i=0; i<tables.length; i++) {
                Configuration table = tables[i];
                processTable(table,conn,request,results);
              }
              conn.commit();
          } catch (Exception e) {
              if (conn != null) {
                  try {
                      conn.rollback();
                  } catch (SQLException se) {
                      getLogger().debug("There was an error rolling back the 
transaction", se);
                  }
              }
  
              //throw new ProcessingException("Could not add record :position = 
" + currentIndex, e);
              throw new ProcessingException("Could not add record",e);
          } finally {
              if (conn != null) {
                  try {
                      conn.close();
                  } catch (SQLException sqe) {
                      getLogger().warn("There was an error closing the 
datasource", sqe);
                  }
              }
  
              if (datasource != null) this.dbselector.release(datasource);
          }
  
          return Collections.unmodifiableMap(results);
      }
  
      /**
       * Inserts a row or a set of rows into the given table based on the
       * request parameters
       *
       * @param table the table's configuration
       * @param conn the database connection
       * @param request the request
       */
      void processTable(Configuration table, Connection conn, Request request, 
Map results) throws SQLException,ConfigurationException,Exception {
        PreparedStatement statement = null;
        try {
          String query = this.getAddQuery(table);
          getLogger().debug("Add query: "+query);
          statement = conn.prepareStatement(query);
          Configuration[] keys = table.getChild("keys").getChildren("key");
          Configuration[] values = 
table.getChild("values").getChildren("value");
          int currentIndex = 1;
          boolean manyrows = false;
          int wildcardIndex = -1;
          String wildcardParam = null;
          for (int i=0; i<keys.length; i++) {
            wildcardParam = keys[i].getAttribute("param");
            if ((wildcardIndex = wildcardParam.indexOf('*')) != -1) {
              manyrows = true;
              break;
            }
          }
          if (manyrows) {
            /**
             * This table has a column with a wildcard, so we're going
             * to be inserting n rows, where 0 <= n
             */
            String prefix = wildcardParam.substring(0,wildcardIndex);
            String suffix;
            if (wildcardParam.length() >= wildcardIndex+1) {
              suffix = wildcardParam.substring(wildcardIndex+1);
            } else {
              suffix = "";
            }
            Enumeration names = request.getParameterNames();
            SortedSet matchset = new TreeSet();
            while (names.hasMoreElements()) {
              String name = (String)names.nextElement();
              if (name.startsWith(prefix) && name.endsWith(suffix)) {
                String wildcard = name.substring(prefix.length());
                wildcard = 
wildcard.substring(0,wildcard.length()-suffix.length());
                matchset.add(wildcard);
              }
            }
            Iterator iterator = matchset.iterator();
            int rowIndex = 1;
            while (iterator.hasNext()) {
              String wildcard = (String)iterator.next();
              currentIndex = 1;
              for (int j=0; j<keys.length; j++) {
                String myparam = 
getActualParam(keys[j].getAttribute("param"),wildcard);
                currentIndex += 
setKey(table,keys[j],conn,statement,currentIndex,request,myparam,results);
              }
              for (int j=0; j<values.length; j++) {
                String myparam = 
getActualParam(values[j].getAttribute("param"),wildcard);
                
this.setColumn(statement,currentIndex,request,values[j],myparam,request.getParameter(myparam),rowIndex);
                currentIndex++;
              }
              statement.execute();
              rowIndex++;
            }
          } else {
            /**
             * This table has no wildcard columns, so we're going to
             * be inserting 1 row.
             */
            for (int i = 0; i < keys.length; i++) {
              currentIndex += 
setKey(table,keys[i],conn,statement,currentIndex,request,keys[i].getAttribute("param",""),results);
            }
            for (int i = 0; i < values.length; i++, currentIndex++) {
              this.setColumn(statement, currentIndex, request, values[i]);
            }
            statement.execute();
            /** Done processing table **/
          }
        } finally {
          try {
            if (statement != null) {
              statement.close();
            }
          } catch (SQLException e) {}
        }
      }
  
      /**
       * Sets the key value on the prepared statement. There are four modes:
       *
       * <dl>
       *   <dt>automatic (default)</dt>
       *   <dd>let the database automatically create the key. note this
       *       prohibits the action from storing the key value anywhere.</dd>
       *   <dt>manual</dt>
       *   <dd>create the key value using SELECT(dbcol)+1 from TABLE</dd>
       *   <dt>form</dt>
       *   <dd>look for the key value in the request parameters</dd>
       *   <dt>request-attribute</dt>
       *   <dd>look for the key value in the request attributes</dd>
       * </dl>
       *
       * This method has a couple of side effects. If the mode is manual,
       * the key value is stored in the request object's attributes for use
       * by other inserts. The key is the string "key:TABLENAME:DBCOL".
       * This method also puts the value of manually created keys in the results
       * map. That key is simply the value of the dbcol attribute. Note this
       * stuff is definitely up in the air.
       *
       * @param table the table's configuration object
       * @param key the key's configuration object
       * @param conn the database connection
       * @param statement the insert statement
       * @param currentIndex the position of the key column
       * @param request the request object
       * @param param the actual name of the request parameter
       * @return the number of columns by which to increment the currentIndex
       */
      int setKey(Configuration table, Configuration key, Connection conn, 
PreparedStatement statement, int currentIndex, Request request, String param, 
Map results) throws ConfigurationException, SQLException,Exception {
        String mode = key.getAttribute("mode","automatic");
        String keyname = new 
StringBuffer("key:").append(table.getAttribute("name"))
                             
.append(':').append(key.getAttribute("dbcol")).toString();
        if ("manual".equals(mode)) {
          /** Set the key value using SELECT MAX(keyname)+1 **/
          String selectQuery = this.getSelectQuery(key);
          PreparedStatement select_statement = 
conn.prepareStatement(selectQuery);
          ResultSet set = select_statement.executeQuery();
          set.next();
          int value = set.getInt("maxid") + 1;
          statement.setInt(currentIndex, value);
          getLogger().debug("Manually setting key to "+value);
          setRequestAttribute(request,keyname,new Integer(value));
          results.put(key.getAttribute("dbcol"),String.valueOf(value));
          set.close();
          select_statement.close();
          return 1;
        } else if ("form".equals(mode)) {
          /** Set the key value from the request **/
          getLogger().debug("Setting key from form");
          this.setColumn(statement, currentIndex, request, key, param);
          return 1;
        } else if ("request-attribute".equals(mode)) {
          Integer value = 
(Integer)getRequestAttribute(request,key.getAttribute("request-attribute-name"));
          getLogger().debug("Setting key from request attribute "+value);
          statement.setInt(currentIndex,value.intValue());
          return 1;
        } else {
          getLogger().debug("Automatically setting key");
          /** The database automatically creates a key value **/
          return 0;
        }
      }
  
      /**
       * Returns the actual name of the parameter. If the name contains
       * no wildcard, the param is returned untouched, otherwise the
       * wildcard value is substituted for the * character. This probably
       * doesn't deserve a method unto itself, but I can imagine wanting
       * to use a more sophisticated matching and substitution algorithm.
       *
       * @param param the name of the parameter, possibly with a wildcard char
       * @param wildcard the wildcard value
       * @return the actual name of the parameter
       */
      String getActualParam(String param, String wildcard) {
        int index;
        if ((index = param.indexOf('*')) != -1) {
          return param.substring(0,index)+wildcard+param.substring(index+1);
        } else {
          return param;
        }
      }
  
      /**
       * Get the String representation of the PreparedStatement.  This is
       * mapped to the Configuration object itself, so if it doesn't exist,
       * it will be created.
       *
       * @param table the table's configuration object
       * @return the insert query as a string
       */
      protected String getAddQuery(Configuration table) throws 
ConfigurationException {
          String query = null;
          synchronized (DatabaseAddAction.addStatements) {
              query = (String) DatabaseAddAction.addStatements.get(table);
              if (query == null) {
                  Configuration[] values = 
table.getChild("values").getChildren("value");
                  Configuration[] keys = 
table.getChild("keys").getChildren("key");
  
                  StringBuffer queryBuffer = new StringBuffer("INSERT INTO ");
                  queryBuffer.append(table.getAttribute("name"));
                  queryBuffer.append(" (");
  
                  int numKeys = 0;
  
                  for (int i = 0; i < keys.length; i++) {
                      String mode = keys[i].getAttribute("mode", "automatic");
                      if ("manual".equals(mode) || "form".equals(mode) || 
"request-attribute".equals(mode)) {
                          if (i > 0) {
                              queryBuffer.append(", ");
                          }
  
                          queryBuffer.append(keys[i].getAttribute("dbcol"));
                          this.setSelectQuery(table.getAttribute("name"), 
keys[i]);
                          numKeys++;
                      }
                  }
  
                  int numValues = 0;
  
                  for (int i = 0; i < values.length; i++) {
                      if ((numKeys + numValues) > 0) {
                          queryBuffer.append(", ");
                      }
  
                      queryBuffer.append(values[i].getAttribute("dbcol"));
                      numValues++;
                  }
  
                  queryBuffer.append(") VALUES (");
  
                  int numParams = numValues + numKeys;
  
                  for (int i = 0; i < numParams; i++) {
                      if (i > 0) {
                          queryBuffer.append(", ");
                      }
  
                      queryBuffer.append("?");
                  }
  
                  queryBuffer.append(")");
  
                  query = queryBuffer.toString();
  
                  DatabaseAddAction.addStatements.put(table, query);
              }
          }
  
          return query;
      }
  
      /**
       * Set the String representation of the MaxID lookup statement.  This is
       * mapped to the Configuration object itself, so if it doesn't exist,
       * it will be created.
       */
      protected final synchronized void setSelectQuery(String tableName, 
Configuration entry) throws ConfigurationException {
          StringBuffer queryBuffer = new StringBuffer("SELECT max(");
          queryBuffer.append(entry.getAttribute("dbcol"));
          queryBuffer.append(") AS maxid FROM ");
          queryBuffer.append(tableName);
  
          DatabaseAddAction.selectStatements.put(entry, queryBuffer.toString());
      }
  
      protected final synchronized String getSelectQuery(Configuration entry) 
throws ConfigurationException {
          return (String) DatabaseAddAction.selectStatements.get(entry);
      }
  }
  
  
  
  1.1                  
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/acting/DatabaseAuthenticatorAction.java
  
  Index: DatabaseAuthenticatorAction.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
      [EMAIL PROTECTED]
  
   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  <[EMAIL PROTECTED]>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  package org.apache.cocoon.acting;
  
  import org.apache.avalon.excalibur.datasource.DataSourceComponent;
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.parameters.Parameters;
  import org.apache.avalon.framework.thread.ThreadSafe;
  import org.apache.cocoon.Constants;
  import org.apache.cocoon.environment.ObjectModelHelper;
  import org.apache.cocoon.environment.Redirector;
  import org.apache.cocoon.environment.Request;
  import org.apache.cocoon.environment.Session;
  import org.apache.cocoon.environment.SourceResolver;
  
  import java.sql.Connection;
  import java.sql.ResultSet;
  import java.sql.Statement;
  import java.util.Collections;
  import java.util.HashMap;
  import java.util.Map;
  
  /**
   * This action is used to authenticate user by comparing several request
   * fields (username, password) with the values in database. The description of
   * the process is given via external xml description file simiar to the one
   * used for all actions derived from AbstractDatabaseAction.
   * <pre>
   * &lt;root&gt;
   *         &lt;connection&gt;personnel&lt;/connection&gt;
   *         &lt;table name="users_table&gt;
   *                 &lt;select dbcol="username" request-param="username"
   *                 to-session="username"/&gt;
   *                 &lt;select dbcol="password" request-param="password"
   *                 nullable="yes"/&gt;
   *                 &lt;select dbcol="role" to-session="role" 
type="string"/&gt;
   *                 &lt;select dbcol="skin" to-session="skin" 
type="string"/&gt;
   *         &lt;/table&gt;
   * &lt;/root&gt;
   * </pre>
   * The values specified via "request-param" describe the name of HTTP request
   * parameter, "dbcol" indicates matching database column, "nullable" means
   * that request-param which is null or empty will not be included in the WHERE
   * clause. This way you can enable accounts with empty passwords, etc.
   * "to-session" attribute indicates under which name the value obtained from
   * database should be stored in the session. Of course new session is created
   * when authorization is successfull. The "type" attribute can be either
   * string, long or double and alters the type of object stored in session.
   * Additionally all parameters that are
   * propagated to the session are made available to the sitemap via {name}
   * expression.
   *
   * If there is no need to touch the session object, providing just one-time
   * verification, you can specify action parameter "create-session" to "no" or
   * "false". No values are then propagated to the sesion and session object is
   * not verified.
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Martin Man</a>
   * @version CVS $Id: DatabaseAuthenticatorAction.java,v 1.1 2002/10/18 
14:04:27 haul Exp $
   */
  public class DatabaseAuthenticatorAction extends AbstractDatabaseAction 
implements ThreadSafe
  {
      /**
       * Main invocation routine.
       */
      public Map act (Redirector redirector, SourceResolver resolver, Map 
objectModel, String src,
              Parameters parameters) throws Exception {
          DataSourceComponent datasource = null;
          Connection conn = null;
          Statement st = null;
          ResultSet rs = null;
  
          // read global parameter settings
          boolean reloadable = Constants.DESCRIPTOR_RELOADABLE_DEFAULT;
  
          if (this.settings.containsKey("reloadable")) {
              reloadable = Boolean.valueOf((String) 
this.settings.get("reloadable")).booleanValue();
          }
  
          // read local settings
          try {
              Configuration conf = this.getConfiguration (
                      parameters.getParameter ("descriptor", (String) 
this.settings.get("descriptor")),
              resolver,
              parameters.getParameterAsBoolean("reloadable",reloadable));
              boolean cs = true;
              String create_session = parameters.getParameter ("create-session",
                                   (String) 
this.settings.get("create-session"));
              if (create_session != null &&
                      ("no".equals (create_session.trim ()) || "false".equals 
(create_session.trim ()))) {
                  cs = false;
              }
  
              datasource = this.getDataSource(conf);
              conn = datasource.getConnection();
              Request req = ObjectModelHelper.getRequest(objectModel);
  
              /* check request validity */
              if (req == null) {
                  getLogger ().debug ("DBAUTH: no request object");
                  return null;
              }
  
              String query = this.getAuthQuery (conf, req);
              if (query == null) {
                  getLogger ().debug ("DBAUTH: have not got query");
                  req.setAttribute("message", "The authenticator is 
misconfigured");
                  return null;
              }
  
              getLogger ().debug ("DBAUTH: query is: " + query);
              st = conn.createStatement ();
              rs = st.executeQuery (query);
  
              if (rs.next ()) {
                  getLogger ().debug ("DBAUTH: authorized successfully");
                  Session session = null;
  
                  if (cs) {
                      session = req.getSession (false);
                      if (session != null)
                          session.invalidate ();
                      session = req.getSession (true);
                      if (session == null)
                          return null;
                      getLogger ().debug ("DBAUTH: session created");
                  } else {
                      getLogger ().debug ("DBAUTH: leaving session untouched");
                  }
  
                  HashMap actionMap = this.propagateParameters (conf, rs,
                          session);
                  if(!conn.getAutoCommit()) {
                      conn.commit();
                  }
                  return Collections.unmodifiableMap (actionMap);
              }
              if(!conn.getAutoCommit()) {
                  conn.rollback();
              }
  
              req.setAttribute("message", "The username or password were 
incorrect, please check your CAPS LOCK key and try again.");
              getLogger ().debug ("DBAUTH: no results for query");
          } catch (Exception e) {
              if (conn != null) {
                  try {
                      if(!conn.getAutoCommit()) {
                          conn.rollback();
                      }
                  } catch (Exception se) {/* ignore */}
              }
              getLogger().debug ("exception: ", e);
              return null;
          } finally {
              if (rs != null) rs.close();
              if (st != null) st.close();
              if (conn != null) {
                  try {
                      conn.close();
                  } catch (Exception e) {/* ignore */}
              }
          }
          return null;
      }
  
      private String getAuthQuery (Configuration conf, Request req) {
          boolean first_constraint = true;
          StringBuffer queryBuffer = new StringBuffer ("SELECT ");
          StringBuffer queryBufferEnd = new StringBuffer ("");
          String dbcol, request_param, request_value, nullstr;
          boolean nullable = false;
          Configuration table = conf.getChild ("table");
          Configuration[] select = table.getChildren ("select");
          try {
              for (int i = 0; i < select.length; i ++) {
                  if (i != 0)
                      queryBuffer.append (", ");
                  dbcol = select[i].getAttribute ("dbcol");
                  queryBuffer.append (dbcol);
                  try {
                      request_param = select[i].getAttribute ("request-param");
                      if (request_param == null ||
                              request_param.trim().equals ("")) {
                          continue;
                      }
                  } catch (Exception e) {
                      continue;
                  }
                  try {
                      nullstr = select[i].getAttribute ("nullable");
                      if (nullstr != null) nullstr = nullstr.trim ();
                      if ("yes".equals (nullstr) || "true".equals (nullstr)) {
                          nullable = true;
                      }
                  } catch (Exception e1) {
                  }
                  /* if there is a request parameter name,
                   * but not the value, we exit immediately do
                   * that authorization fails authomatically */
                  request_value = req.getParameter (
                          request_param);
                  if (request_value == null || request_value.trim().equals 
("")) {
                      // value is null
                      if (!nullable) {
                          getLogger ().debug ("DBAUTH: request-param "
                                  + request_param + " does not exist");
                          return null;
                      }
                  } else {
                      if (!first_constraint)
                          queryBufferEnd.append (" AND ");
                      queryBufferEnd.append 
(dbcol).append("='").append(request_value).append("'");
                      first_constraint = false;
                  }
              }
              queryBuffer.append (" FROM ");
              queryBuffer.append (table.getAttribute ("name"));
              if (!queryBufferEnd.toString ().trim ().equals (""))
                  queryBuffer.append (" WHERE ").append 
(queryBufferEnd.toString ());
              return queryBuffer.toString ();
          } catch (Exception e) {
              getLogger ().debug ("DBAUTH: got exception: " + e);
              return null;
          }
      }
  
      private HashMap propagateParameters (Configuration conf, ResultSet rs,
              Session session) {
          Configuration table = conf.getChild ("table");
          Configuration[] select = table.getChildren ("select");
          String dbcol, session_param, type;
          HashMap map = new HashMap();
          try {
              for (int i = 0; i < select.length; i ++) {
                  dbcol = select[i].getAttribute ("dbcol");
                  try {
                      session_param = select[i].getAttribute ("to-session");
                      if (session_param != null &&
                              !session_param.trim().equals ("")) {
                          String s = rs.getString (i + 1);
                          /* propagate to session */
                          try {
                              type = select[i].getAttribute ("type");
                          } catch (Exception e) {
                              type = null;
                          }
                          if (type == null || "".equals (type.trim ())) {
                              type = "string";
                          }
                          Object o = null;
                          if ("string".equals (type)) {
                              o = s;
                          } else if ("long".equals (type)) {
                              Long l = Long.decode (s);
                              o = l;
                          } else if ("double".equals (type)) {
                              Double d = Double.valueOf (s);
                              o = d;
                          }
                          if (session != null) {
                              session.setAttribute (session_param, o);
                              getLogger ().debug ("DBAUTH: propagating param "
                                      + session_param + "=" + s);
                          }
                          map.put (session_param, o);
                      }
                  } catch (Exception e) {
                  }
              }
              return map;
          } catch (Exception e) {
              getLogger().debug("exception: ", e);
          }
          return null;
      }
  }
  
  
  
  
  1.1                  
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/acting/DatabaseCookieAuthenticatorAction.java
  
  Index: DatabaseCookieAuthenticatorAction.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
      [EMAIL PROTECTED]
  
   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  <[EMAIL PROTECTED]>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  package org.apache.cocoon.acting;
  
  import org.apache.avalon.excalibur.datasource.DataSourceComponent;
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.parameters.Parameters;
  import org.apache.avalon.framework.thread.ThreadSafe;
  import org.apache.cocoon.Constants;
  import org.apache.cocoon.components.language.markup.xsp.XSPCookieHelper;
  import org.apache.cocoon.environment.ObjectModelHelper;
  import org.apache.cocoon.environment.Redirector;
  import org.apache.cocoon.environment.Request;
  import org.apache.cocoon.environment.Session;
  import org.apache.cocoon.environment.SourceResolver;
  
  import java.sql.Connection;
  import java.sql.ResultSet;
  import java.sql.Statement;
  import java.util.Collections;
  import java.util.HashMap;
  import java.util.Map;
  
  /**
   *  This action is used to authenticate user by comparing several cookie 
values
   *  (username, password) with the values in database. The description of the
   *  process is given via external xml description file simiar to the one used
   *  for all actions derived from AbstractDatabaseAction. <pre>
   * &lt;root&gt;
   *         &lt;connection&gt;personnel&lt;/connection&gt;
   *         &lt;table name="users_table&gt;
   *                 &lt;select dbcol="username" cookie-name="username"
   *                 to-session="username"/&gt;
   *                 &lt;select dbcol="password" cookie-name="password"
   *                 nullable="yes"/&gt;
   *                 &lt;select dbcol="role" to-session="role" 
type="string"/&gt;
   *                 &lt;select dbcol="skin" to-session="skin" 
type="string"/&gt;
   *         &lt;/table&gt;
   * &lt;/root&gt;
   * </pre> The values specified via "cookie-name" describe the name of the
   *  cookie, "dbcol" indicates matching database column, "nullable" means that
   *  cookie-name which is null or empty will not be included in the WHERE 
clause.
   *  This way you can enable accounts with empty passwords, etc. "to-session"
   *  attribute indicates under which name the value obtained from database 
should
   *  be stored in the session. Of course new session is created when
   *  authorization is successfull. The "type" attribute can be either string,
   *  long or double and alters the type of object stored in session. 
Additionally
   *  all parameters that are propagated to the session are made available to 
the
   *  sitemap via {name} expression. If there is no need to touch the session
   *  object, providing just one-time verification, you can specify action
   *  parameter "create-session" to "no" or "false". No values are then 
propagated
   *  to the sesion and session object is not verified. If you want to append
   *  attributes to the session without creating a new one, specify action
   *  parameter "append-session" to "yes" or "true".
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Paolo Scaffardi</a>
   * @version CVS $Id: DatabaseCookieAuthenticatorAction.java,v 1.1 2002/10/18 
14:04:27 haul Exp $
   */
  public class DatabaseCookieAuthenticatorAction extends AbstractDatabaseAction 
implements ThreadSafe {
  
      /**
       *  Main invocation routine.
       *
       * @param  redirector     Description of Parameter
       * @param  resolver       Description of Parameter
       * @param  objectModel    Description of Parameter
       * @param  src            Description of Parameter
       * @param  parameters     Description of Parameter
       * @return                Description of the Returned Value
       * @exception  Exception  Description of Exception
       */
      public Map act(Redirector redirector, SourceResolver resolver, Map 
objectModel, String src,
              Parameters parameters)
          throws Exception {
          DataSourceComponent datasource = null;
          Connection conn = null;
          Statement st = null;
          ResultSet rs = null;
  
          // read global parameter settings
          boolean reloadable = Constants.DESCRIPTOR_RELOADABLE_DEFAULT;
  
          if (this.settings.containsKey("reloadable")) {
              reloadable = Boolean.valueOf((String) 
this.settings.get("reloadable")).booleanValue();
          }
  
          // read local settings
          try {
              Configuration conf = this.getConfiguration(
                      parameters.getParameter("descriptor", (String) 
this.settings.get("descriptor")),
                      resolver,
                      parameters.getParameterAsBoolean("reloadable", 
reloadable));
              boolean cs = true;
              boolean as = false;
              String create_session = parameters.getParameter("create-session",
                      (String) this.settings.get("create-session"));
              String
                      append_session = parameters.getParameter("append-session",
                      (String) this.settings.get("append-session"));
  
              if (create_session != null &&
                      ("no".equals(create_session.trim()) || 
"false".equals(create_session.trim()))) {
                  cs = false;
              }
              if (append_session != null &&
                      ("yes".equals(append_session.trim()) || 
"true".equals(append_session.trim()))) {
                  as = true;
              }
  
              datasource = this.getDataSource(conf);
              conn = datasource.getConnection();
              Request req = ObjectModelHelper.getRequest(objectModel);
  
              /*
               *  check request validity
               */
              if (req == null) {
                  if (getLogger().isDebugEnabled()) {
                      getLogger().debug("DBCOOKIEAUTH: no request object");
                  }
                  return null;
              }
  
              String query = this.getAuthQuery(objectModel, conf, req);
              if (query == null) {
                  if (getLogger().isDebugEnabled()) {
                      getLogger().debug("DBCOOKIEAUTH: have not got query");
                  }
                  req.setAttribute("message", "The authenticator is 
misconfigured");
                  return null;
              }
  
              if (getLogger().isDebugEnabled()) {
                  getLogger().debug("DBCOOKIEAUTH: query is: " + query);
              }
              st = conn.createStatement();
              rs = st.executeQuery(query);
  
              if (rs.next()) {
                  if (getLogger().isDebugEnabled()) {
                      getLogger().debug("DBCOOKIEAUTH: authorized 
successfully");
                  }
                  Session session = null;
  
                  if (cs) {
                      session = req.getSession(false);
                      if (session != null) {
                          if (as == false) {
                              session.invalidate();
                              session = req.getSession(true);
                              if (getLogger().isDebugEnabled()) {
                                  getLogger().debug("DBCOOKIEAUTH: session 
invalidated");
                              }
                          }
                      } else {
                          session = req.getSession(true);
                      }
  
                      if (session == null) {
                          return null;
                      }
  
                      if (getLogger().isDebugEnabled()) {
                          if (as) {
                              getLogger().debug("DBCOOKIEAUTH: appending to 
session");
                          } else {
                              getLogger().debug("DBCOOKIEAUTH: session 
created");
                          }
                      }
                  } else {
                      if (getLogger().isDebugEnabled()) {
                          getLogger().debug("DBCOOKIEAUTH: leaving session 
untouched");
                      }
                  }
  
                  HashMap actionMap = this.propagateParameters(conf, rs,
                          session);
                  if (!conn.getAutoCommit()) {
                      conn.commit();
                  }
                  return Collections.unmodifiableMap(actionMap);
              }
              if (!conn.getAutoCommit()) {
                  conn.rollback();
              }
  
              req.setAttribute("message", "The username or password were 
incorrect, please check your CAPS LOCK key and try again.");
              if (getLogger().isDebugEnabled()) {
                  getLogger().debug("DBCOOKIEAUTH: no results for query");
              }
          } catch (Exception e) {
              if (conn != null) {
                  try {
                      if (!conn.getAutoCommit()) {
                          conn.rollback();
                      }
                  } catch (Exception se) {
                      /*
                       *  ignore
                       */
                  }
              }
              getLogger().error("Exception: ", e);
              return null;
          } finally {
              if (rs != null) {
                  rs.close();
              }
              if (st != null) {
                  st.close();
              }
              if (conn != null) {
                  try {
                      conn.close();
                  } catch (Exception e) {
                      /*
                       *  ignore
                       */
                  }
              }
          }
          return null;
      }
  
  
      /**
       *  Gets the authQuery attribute of the DatabaseCookieAuthenticatorAction
       *  object
       *
       * @param  objectModel  Description of Parameter
       * @param  conf         Description of Parameter
       * @param  req          Description of Parameter
       * @return              The authQuery value
       */
      private String getAuthQuery(Map objectModel, Configuration conf, Request 
req) {
          boolean first_constraint = true;
          StringBuffer queryBuffer = new StringBuffer("SELECT ");
          StringBuffer queryBufferEnd = new StringBuffer("");
          String dbcol;
          String cookie_name;
          String cookie_value;
          String nullstr;
          boolean nullable = false;
          Configuration table = conf.getChild("table");
          Configuration[] select = table.getChildren("select");
          try {
              for (int i = 0; i < select.length; i++) {
                  if (i != 0) {
                      queryBuffer.append(", ");
                  }
                  dbcol = select[i].getAttribute("dbcol");
                  queryBuffer.append(dbcol);
                  try {
                      cookie_name = select[i].getAttribute("cookie-name");
                      if (cookie_name == null ||
                              cookie_name.trim().equals("")) {
                          continue;
                      }
                  } catch (Exception e) {
                      continue;
                  }
                  try {
                      nullstr = select[i].getAttribute("nullable");
                      if (nullstr != null) {
                          nullstr = nullstr.trim();
                      }
                      if ("yes".equals(nullstr) || "true".equals(nullstr)) {
                          nullable = true;
                      }
                  } catch (Exception e1) {
                  }
                  /*
                   *  if there is a cookie name,
                   *  but not the value, we exit immediately do
                   *  that authorization fails authomatically
                   */
                  cookie_value = XSPCookieHelper.getCookie(objectModel, 
cookie_name, -1).getValue();
  
                  if (cookie_value == null || cookie_value.trim().equals("")) {
                      // value is null
                      if (!nullable) {
                          if (getLogger().isDebugEnabled()) {
                              getLogger().debug("DBCOOKIEAUTH: cookie-name "
                                          + cookie_name + " does not exist");
                          }
                          return null;
                      }
                  } else {
                      if (!first_constraint) {
                          queryBufferEnd.append(" AND ");
                      }
                      queryBufferEnd.append(dbcol + "='" + cookie_value + "'");
                      first_constraint = false;
                  }
              }
              queryBuffer.append(" FROM ");
              queryBuffer.append(table.getAttribute("name"));
              if (!queryBufferEnd.toString().trim().equals("")) {
                  queryBuffer.append(" WHERE ").append(queryBufferEnd);
              }
              return queryBuffer.toString();
          } catch (Exception e) {
              getLogger().error("Exception: ",e);
              return null;
          }
      }
  
  
      /**
       *  Description of the Method
       *
       * @param  conf     Description of Parameter
       * @param  rs       Description of Parameter
       * @param  session  Description of Parameter
       * @return          Description of the Returned Value
       */
      private HashMap propagateParameters(Configuration conf, ResultSet rs,
              Session session) {
          Configuration table = conf.getChild("table");
          Configuration[] select = table.getChildren("select");
          String dbcol;
          String session_param;
          String type;
          HashMap map = new HashMap();
          try {
              for (int i = 0; i < select.length; i++) {
                  dbcol = select[i].getAttribute("dbcol");
                  try {
                      session_param = select[i].getAttribute("to-session");
                      if (session_param != null &&
                              !session_param.trim().equals("")) {
                          String s = rs.getString(i + 1);
                          /*
                           *  propagate to session
                           */
                          try {
                              type = select[i].getAttribute("type");
                          } catch (Exception e) {
                              type = null;
                          }
                          if (type == null || "".equals(type.trim())) {
                              type = "string";
                          }
                          Object o = null;
                          if ("string".equals(type)) {
                              o = s;
                          } else if ("long".equals(type)) {
                              Long l = Long.decode(s);
                              o = l;
                          } else if ("double".equals(type)) {
                              Double d = Double.valueOf(s);
                              o = d;
                          }
                          if (session != null) {
                              session.setAttribute(session_param, o);
                              if (getLogger().isDebugEnabled()) {
                                  getLogger().debug("DBCOOKIEAUTH: propagating 
param "
                                              + session_param + "=" + s);
                              }
                          }
                          map.put(session_param, o);
                      }
                  } catch (Exception e) {
                  }
              }
              return map;
          } catch (Exception e) {
              getLogger().error("Exception: ", e);
          }
          return null;
      }
  }
  
  
  
  
  1.1                  
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/acting/DatabaseDeleteAction.java
  
  Index: DatabaseDeleteAction.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
      [EMAIL PROTECTED]
  
   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  <[EMAIL PROTECTED]>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  package org.apache.cocoon.acting;
  
  import org.apache.avalon.excalibur.datasource.DataSourceComponent;
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.configuration.ConfigurationException;
  import org.apache.avalon.framework.parameters.Parameters;
  import org.apache.avalon.framework.thread.ThreadSafe;
  import org.apache.cocoon.Constants;
  import org.apache.cocoon.ProcessingException;
  import org.apache.cocoon.environment.ObjectModelHelper;
  import org.apache.cocoon.environment.Redirector;
  import org.apache.cocoon.environment.Request;
  import org.apache.cocoon.environment.SourceResolver;
  
  import java.sql.Connection;
  import java.sql.PreparedStatement;
  import java.sql.SQLException;
  import java.util.HashMap;
  import java.util.Map;
  
  /**
   * Delete a record from a database.  This Action assumes that all
   * dependant data is either automatically cleaned up by cascading
   * deletes, or that multiple instances of this action are being used
   * in the correct order.  In other words, it removes one record by
   * the keys.
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Berin Loritsch</a>
   * @version CVS $Id: DatabaseDeleteAction.java,v 1.1 2002/10/18 14:04:27 haul 
Exp $
   */
  public final class DatabaseDeleteAction extends AbstractDatabaseAction 
implements ThreadSafe {
      private static final Map deleteStatements = new HashMap();
  
      /**
       * Delete a record from the database.  This action assumes that
       * the file referenced by the "descriptor" parameter conforms
       * to the AbstractDatabaseAction specifications.
       */
      public final Map act(Redirector redirector, SourceResolver resolver, Map 
objectModel, String source, Parameters param) throws Exception {
          DataSourceComponent datasource = null;
          Connection conn = null;
          int currentIndex = 0;
  
          // read global parameter settings
          boolean reloadable = Constants.DESCRIPTOR_RELOADABLE_DEFAULT;
          if (this.settings.containsKey("reloadable"))
              reloadable = Boolean.valueOf((String) 
this.settings.get("reloadable")).booleanValue();
          // read local parameter settings
          try {
              Configuration conf =
                  this.getConfiguration(param.getParameter("descriptor", 
(String) this.settings.get("descriptor")), resolver,
                                        
param.getParameterAsBoolean("reloadable",reloadable));
  
              String query = this.getDeleteQuery(conf);
              datasource = this.getDataSource(conf);
              conn = datasource.getConnection();
              Request request = ObjectModelHelper.getRequest(objectModel);
  
              if (conn.getAutoCommit()) {
                  conn.setAutoCommit(false);
              }
  
              PreparedStatement statement = conn.prepareStatement(query);
  
              Configuration[] keys = 
conf.getChild("table").getChild("keys").getChildren("key");
  
              for (int i = 0; i < keys.length; i++) {
                  this.setColumn(statement, i + 1, request, keys[i]);
              }
  
              int rows = statement.executeUpdate();
              conn.commit();
              statement.close();
  
              if(rows > 0){
                  request.setAttribute("rows", Integer.toString(rows));
                  return EMPTY_MAP;
              }
          } catch (Exception e) {
              if (conn != null) {
                  conn.rollback();
              }
  
              throw new ProcessingException("Could not delete record :position 
= " + currentIndex, e);
          } finally {
              if (conn != null) {
                  try {
                      conn.close();
                  } catch (SQLException sqe) {
                      getLogger().warn("There was an error closing the 
datasource", sqe);
                  }
              }
  
              if (datasource != null) this.dbselector.release(datasource);
          }
  
          return null;
      }
  
      /**
       * Get the String representation of the PreparedStatement.  This is
       * mapped to the Configuration object itself, so if it doesn't exist,
       * it will be created.
       */
      private final String getDeleteQuery(Configuration conf) throws 
ConfigurationException {
          String query = null;
  
          synchronized (DatabaseDeleteAction.deleteStatements) {
              query = (String) DatabaseDeleteAction.deleteStatements.get(conf);
  
              if (query == null) {
                  Configuration table = conf.getChild("table");
                  Configuration[] keys = 
table.getChild("keys").getChildren("key");
  
                  StringBuffer queryBuffer = new StringBuffer("DELETE FROM ");
                  queryBuffer.append(table.getAttribute("name"));
                  queryBuffer.append(" WHERE ");
  
                  for (int i = 0; i < keys.length; i++) {
                      if (i > 0) {
                          queryBuffer.append(" AND ");
                      }
  
                      queryBuffer.append((keys[i]).getAttribute("dbcol"));
                      queryBuffer.append(" = ?");
                  }
  
                  query = queryBuffer.toString();
  
                  DatabaseDeleteAction.deleteStatements.put(conf, query);
              }
          }
  
          return query;
      }
  }
  
  
  
  1.1                  
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/acting/DatabaseSelectAction.java
  
  Index: DatabaseSelectAction.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
      [EMAIL PROTECTED]
  
   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  <[EMAIL PROTECTED]>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  package org.apache.cocoon.acting;
  
  import org.apache.avalon.excalibur.datasource.DataSourceComponent;
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.configuration.ConfigurationException;
  import org.apache.avalon.framework.parameters.Parameters;
  import org.apache.avalon.framework.thread.ThreadSafe;
  import org.apache.cocoon.Constants;
  import org.apache.cocoon.ProcessingException;
  import org.apache.cocoon.environment.ObjectModelHelper;
  import org.apache.cocoon.environment.Redirector;
  import org.apache.cocoon.environment.Request;
  import org.apache.cocoon.environment.SourceResolver;
  
  import java.sql.Connection;
  import java.sql.PreparedStatement;
  import java.sql.ResultSet;
  import java.sql.SQLException;
  import java.util.HashMap;
  import java.util.Map;
  
  /**
   * Select a record from a database. If request parameters are present,
   * their values are used to populate request attributes. Otherwise,
   * values from database are used.
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Berin Loritsch</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Vadim Gritsenko</a>
   * @version CVS $Id: DatabaseSelectAction.java,v 1.1 2002/10/18 14:04:27 haul 
Exp $
   */
  public class DatabaseSelectAction extends AbstractDatabaseAction implements 
ThreadSafe {
  
      private static final Map selectStatements = new HashMap();
  
      /**
       * Select a record from the database.  This action assumes that
       * the file referenced by the "descriptor" parameter conforms
       * to the AbstractDatabaseAction specifications.
       */
      public Map act(Redirector redirector, SourceResolver resolver, Map 
objectModel, String source, Parameters param) throws Exception {
          DataSourceComponent datasource = null;
          Connection conn = null;
          int currentIndex = 0;
  
          // read global parameter settings
          boolean reloadable = Constants.DESCRIPTOR_RELOADABLE_DEFAULT;
          if (this.settings.containsKey("reloadable"))
              reloadable = Boolean.valueOf((String) 
this.settings.get("reloadable")).booleanValue();
          // read local parameter settings
          try {
              Configuration conf =
                  this.getConfiguration(param.getParameter("descriptor", 
(String) this.settings.get("descriptor")),
                                        resolver,
                                        
param.getParameterAsBoolean("reloadable",reloadable));
  
              Request request = ObjectModelHelper.getRequest(objectModel);
  
              Configuration[] keys = 
conf.getChild("table").getChild("keys").getChildren("key");
              Configuration[] values = 
conf.getChild("table").getChild("values").getChildren("value");
  
              PreparedStatement statement = null;
              ResultSet rset = null;
              boolean result = false;
  
              for (int i = 0; i < keys.length; i++) {
                  final String parameter = keys[i].getAttribute("param");
                  Object value = request.getParameter(parameter);
                  if (value == null || "".equals(value)) {
                      if (statement == null) {
                          final String query = this.getSelectQuery(conf);
                          datasource = this.getDataSource(conf);
                          conn = datasource.getConnection();
  
                          statement = conn.prepareStatement(query);
                          currentIndex = 1;
                          for (int j = 0; j < keys.length; j++, currentIndex++) 
{
                              this.setColumn(statement, currentIndex, request, 
keys[j]);
                          }
  
                          rset = statement.executeQuery();
                          result = rset.next();
                      }
  
                      if (result)
                          value = this.getColumn(rset, request, keys[i]);
                  }
  
                  if (value != null)
                      request.setAttribute(parameter, value.toString());
              }
  
              for (int i = 0; i < values.length; i++) {
                  final String parameter = values[i].getAttribute("param");
                  Object value = request.getParameter(parameter);
                  if (value == null || "".equals(value)) {
                      if (statement == null) {
                          final String query = this.getSelectQuery(conf);
                          datasource = this.getDataSource(conf);
                          conn = datasource.getConnection();
  
                          statement = conn.prepareStatement(query);
                          currentIndex = 1;
                          for (int j = 0; j < keys.length; j++, currentIndex++) 
{
                              this.setColumn(statement, currentIndex, request, 
keys[j]);
                          }
  
                          rset = statement.executeQuery();
                          result = rset.next();
                      }
  
                      if (result)
                          value = this.getColumn(rset, request, values[i]);
                  }
  
                  if (value != null)
                      request.setAttribute(parameter, value.toString());
              }
  
              if(statement != null)
                  statement.close();
  
              return EMPTY_MAP;
          } catch (Exception e) {
              throw new ProcessingException("Could not prepare statement 
:position = " + currentIndex, e);
          } finally {
              if (conn != null) {
                  try {
                      conn.close();
                  } catch (SQLException sqe) {
                      getLogger().warn("There was an error closing the 
datasource", sqe);
                  }
              }
  
              if (datasource != null) this.dbselector.release(datasource);
          }
  
          // Result is empty map or exception. No null.
      }
  
      /**
       * Get the String representation of the PreparedStatement.  This is
       * mapped to the Configuration object itself, so if it doesn't exist,
       * it will be created.
       */
      protected String getSelectQuery(Configuration conf) throws 
ConfigurationException {
          String query = null;
  
          synchronized (DatabaseSelectAction.selectStatements) {
              query = (String) DatabaseSelectAction.selectStatements.get(conf);
  
              if (query == null) {
                  Configuration table = conf.getChild("table");
                  Configuration[] keys = 
table.getChild("keys").getChildren("key");
                  Configuration[] values = 
table.getChild("values").getChildren("value");
  
                  StringBuffer queryBuffer = new StringBuffer("SELECT ");
                  int index = 0;
                  for (int i = 0; i < keys.length; i++, index++) {
                      if (index > 0) {
                          queryBuffer.append(", ");
                      }
                      queryBuffer.append(keys[i].getAttribute("dbcol"));
                  }
                  for (int i = 0; i < values.length; i++,index++) {
                      if (index > 0) {
                          queryBuffer.append(", ");
                      }
                      queryBuffer.append(values[i].getAttribute("dbcol"));
                  }
  
                  queryBuffer.append(" FROM ");
                  queryBuffer.append(table.getAttribute("name"));
  
                  queryBuffer.append(" WHERE ");
                  for (int i = 0; i < keys.length; i++) {
                      if (i > 0) {
                          queryBuffer.append(" AND ");
                      }
  
                      queryBuffer.append(keys[i].getAttribute("dbcol"));
                      queryBuffer.append(" = ?");
                  }
  
                  query = queryBuffer.toString();
  
                  DatabaseSelectAction.selectStatements.put(conf, query);
              }
          }
  
          return query;
      }
  }
  
  
  
  1.1                  
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/acting/DatabaseUpdateAction.java
  
  Index: DatabaseUpdateAction.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
      [EMAIL PROTECTED]
  
   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  <[EMAIL PROTECTED]>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  package org.apache.cocoon.acting;
  
  import org.apache.avalon.excalibur.datasource.DataSourceComponent;
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.configuration.ConfigurationException;
  import org.apache.avalon.framework.parameters.Parameters;
  import org.apache.avalon.framework.thread.ThreadSafe;
  import org.apache.cocoon.Constants;
  import org.apache.cocoon.ProcessingException;
  import org.apache.cocoon.environment.ObjectModelHelper;
  import org.apache.cocoon.environment.Redirector;
  import org.apache.cocoon.environment.Request;
  import org.apache.cocoon.environment.SourceResolver;
  
  import java.sql.Connection;
  import java.sql.PreparedStatement;
  import java.sql.SQLException;
  import java.util.HashMap;
  import java.util.Map;
  
  /**
   * Update a record in a database.  This Action assumes that there is
   * only one table at a time to update.
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Berin Loritsch</a>
   * @version CVS $Id: DatabaseUpdateAction.java,v 1.1 2002/10/18 14:04:27 haul 
Exp $
   */
  public class DatabaseUpdateAction extends AbstractDatabaseAction implements 
ThreadSafe {
      private static final Map updateStatements = new HashMap();
  
      /**
       * Update a record in the database.  This action assumes that
       * the file referenced by the "descriptor" parameter conforms
       * to the AbstractDatabaseAction specifications.
       */
      public Map act(Redirector redirector, SourceResolver resolver, Map 
objectModel, String source, Parameters param) throws Exception {
          DataSourceComponent datasource = null;
          Connection conn = null;
          int currentIndex = 0;
  
          // read global parameter settings
          boolean reloadable = Constants.DESCRIPTOR_RELOADABLE_DEFAULT;
          if (this.settings.containsKey("reloadable"))
              reloadable = Boolean.valueOf((String) 
this.settings.get("reloadable")).booleanValue();
          // read local parameter settings
          try {
              Configuration conf =
                  this.getConfiguration(param.getParameter("descriptor", 
(String) this.settings.get("descriptor")), resolver,
                                        
param.getParameterAsBoolean("reloadable",reloadable));
  
              String query = this.getUpdateQuery(conf);
              datasource = this.getDataSource(conf);
              conn = datasource.getConnection();
              Request request = ObjectModelHelper.getRequest(objectModel);
  
              if (conn.getAutoCommit()) {
                  conn.setAutoCommit(false);
              }
  
              PreparedStatement statement = conn.prepareStatement(query);
  
              Configuration[] keys = 
conf.getChild("table").getChild("keys").getChildren("key");
              Configuration[] values = 
conf.getChild("table").getChild("values").getChildren("value");
              currentIndex = 1;
  
              for (int i = 0; i < values.length; i++, currentIndex++) {
                  this.setColumn(statement, currentIndex, request, values[i]);
              }
  
              for (int i = 0; i < keys.length; i++, currentIndex++) {
                  this.setColumn(statement, currentIndex, request, keys[i]);
              }
  
              int rows = statement.executeUpdate();
              conn.commit();
              statement.close();
  
              if(rows > 0){
                  request.setAttribute("rows", Integer.toString(rows));
                  return EMPTY_MAP;
              }
          } catch (Exception e) {
              if (conn != null) {
                  conn.rollback();
              }
  
              throw new ProcessingException("Could not update record :position 
= " + currentIndex, e);
          } finally {
              if (conn != null) {
                  try {
                      conn.close();
                  } catch (SQLException sqe) {
                      getLogger().warn("There was an error closing the 
datasource", sqe);
                  }
              }
  
              if (datasource != null) this.dbselector.release(datasource);
          }
  
          return null;
      }
  
      /**
       * Get the String representation of the PreparedStatement.  This is
       * mapped to the Configuration object itself, so if it doesn't exist,
       * it will be created.
       */
      protected String getUpdateQuery(Configuration conf) throws 
ConfigurationException {
          String query = null;
  
          synchronized (DatabaseUpdateAction.updateStatements) {
              query = (String) DatabaseUpdateAction.updateStatements.get(conf);
  
              if (query == null) {
                  Configuration table = conf.getChild("table");
                  Configuration[] keys = 
table.getChild("keys").getChildren("key");
                  Configuration[] values = 
table.getChild("values").getChildren("value");
  
                  StringBuffer queryBuffer = new StringBuffer("UPDATE ");
                  queryBuffer.append(table.getAttribute("name"));
                  queryBuffer.append(" SET ");
  
                  for (int i = 0; i < values.length; i++) {
                      if (i > 0) {
                           queryBuffer.append(", ");
                      }
  
                      queryBuffer.append(values[i].getAttribute("dbcol"));
                      queryBuffer.append(" = ?");
                  }
  
                  queryBuffer.append(" WHERE ");
  
                  for (int i = 0; i < keys.length; i++) {
                      if (i > 0) {
                          queryBuffer.append(" AND ");
                      }
  
                      queryBuffer.append(keys[i].getAttribute("dbcol"));
                      queryBuffer.append(" = ?");
                  }
  
                  query = queryBuffer.toString();
  
                  DatabaseUpdateAction.updateStatements.put(conf, query);
              }
          }
  
          return query;
      }
  }
  
  
  
  1.1                  
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/acting/DbXMLAuthenticatorAction.java
  
  Index: DbXMLAuthenticatorAction.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 2001 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, 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 [EMAIL PROTECTED]
   *
   * 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 (INCLUDING, 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.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  package org.apache.cocoon.acting;
  
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.parameters.Parameters;
  import org.apache.avalon.framework.thread.ThreadSafe;
  
  import org.apache.cocoon.Constants;
  import org.apache.cocoon.environment.ObjectModelHelper;
  import org.apache.cocoon.environment.Redirector;
  import org.apache.cocoon.environment.Request;
  import org.apache.cocoon.environment.Session;
  import org.apache.cocoon.environment.SourceResolver;
  
  import org.apache.xpath.XPathAPI;
  import org.apache.xpath.objects.XObject;
  import org.w3c.dom.Node;
  import org.xmldb.api.DatabaseManager;
  import org.xmldb.api.base.Collection;
  import org.xmldb.api.base.Database;
  import org.xmldb.api.base.ResourceIterator;
  import org.xmldb.api.base.ResourceSet;
  import org.xmldb.api.base.XMLDBException;
  import org.xmldb.api.modules.XMLResource;
  import org.xmldb.api.modules.XPathQueryService;
  
  import java.util.Collections;
  import java.util.HashMap;
  import java.util.Map;
  
  /**
   * This action is used to authenticate user by comparing several request
   * fields (username, password) with the values in a DBXML compliant database.
   * The description of the process is given via external xml description file
   * simiar to the one used for all actions derived from AbstractDatabaseAction.
   *
   * <pre>
   * <root>
   *
   *   <connection>
   *     <driver>org.apache.xindice.client.xmldb.DatabaseImpl</driver>
   *     <base>xmldb:xindice:///db/beta</base>
   *   </connection>
   *
   *   <root name="users>
   *      <select element="username" request-param="username" 
to-session="username"/>
   *      <select element="password" request-param="password" nullable="yes"/>
   *
   *      <select element="role" to-session="role" type="string"/>
   *      <select element="skin" to-session="skin" type="string"/>
   *   </root>
   *
   * </root>
   * </pre>
   *
   * The values specified via "request-param" describe the name of HTTP request
   * parameter, "element" indicates matching document node, "nullable" means
   * that request-param which is null or empty will not be included in the WHERE
   * clause. This way you can enable accounts with empty passwords, etc.
   * "to-session" attribute indicates under which name the value obtained from
   * database should be stored in the session. Of course new session is created
   * when authorization is successfull. The "type" attribute can be either
   * string, long or double and alters the type of object stored in session.
   * Additionally all parameters that are
   * propagated to the session are made available to the sitemap via {name}
   * expression.
   *
   * If there is no need to touch the session object, providing just one-time
   * verification, you can specify action parameter "create-session" to "no" or
   * "false". No values are then propagated to the sesion and session object is
   * not verified.
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Christian Zoffoli</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Martin Man</a>
   * @version 0.2 -- 2002/02/03
   *
   * based on DatabaseAuthenticatorAction created by Martin Man <[EMAIL 
PROTECTED]>
   */
  public class DbXMLAuthenticatorAction extends AbstractDatabaseAction 
implements ThreadSafe
  {
  
    /**
    * Main invocation routine.
    */
    public Map act (Redirector redirector, SourceResolver resolver, Map 
objectModel, String src,
          Parameters parameters) throws Exception {
  
      ResourceSet rs = null;
  
      // read global parameter settings
      boolean reloadable = Constants.DESCRIPTOR_RELOADABLE_DEFAULT;
  
      if (this.settings.containsKey("reloadable")) {
          reloadable = Boolean.valueOf((String) 
this.settings.get("reloadable")).booleanValue();
      }
  
      // read local settings
      try {
          Configuration conf = this.getConfiguration (
            parameters.getParameter ("descriptor", (String) 
this.settings.get("descriptor")),
            resolver,
            parameters.getParameterAsBoolean("reloadable",
            reloadable));
  
  
          boolean cs = true;
          String create_session = parameters.getParameter ("create-session", 
(String) this.settings.get("create-session"));
  
          if (create_session != null && ("no".equals (create_session.trim ()) 
|| "false".equals (create_session.trim ()))) {
            cs = false;
          }
  
          Request req = ObjectModelHelper.getRequest(objectModel);
  
          /* check request validity */
          if (req == null) {
            getLogger ().debug ("DBXMLAUTH: no request object");
            return null;
          }
  
          rs = this.Authenticate( conf, req );
  
          if (rs != null )
          {
            getLogger ().debug ("DBXMLAUTH: authorized successfully");
            Session session = null;
  
            if (cs) {
              session = req.getSession (false);
              if (session != null)
                  session.invalidate ();
              session = req.getSession (true);
              if (session == null)
                  return null;
              getLogger ().debug ("DBXMLAUTH: session created");
            } else {
              getLogger ().debug ("DBXMLAUTH: leaving session untouched");
            }
  
            HashMap actionMap = this.propagateParameters (conf, rs, session);
            return Collections.unmodifiableMap (actionMap);
          } else {
            //getLogger ().debug ("DBXMLAUTH: error ResourceSet is null");
          }
  
          req.setAttribute("message", "The username or password were incorrect, 
please check your CAPS LOCK key and try again.");
          getLogger ().debug ("DBXMLAUTH: no results for query");
  
      } catch (Exception e) {
  
          getLogger().debug ("exception: ", e);
          return null;
      }
  
      return null;
    }
  
  
    private String getAuthQuery ( Configuration conf, Request req )
    {
  
      boolean first_constraint = true;
  
      StringBuffer queryBuffer = new StringBuffer ("//");
      StringBuffer queryBufferEnd = new StringBuffer ("");
  
      String dbcol, request_param, request_value, nullstr;
      boolean nullable = false;
  
      Configuration table = conf.getChild ("root");
      Configuration[] select = table.getChildren ("select");
  
      try {
  
          queryBuffer.append (table.getAttribute ("name"));
  
          for (int i = 0; i < select.length; i ++)
          {
  
            dbcol = "[" + select[i].getAttribute ("element");
  
            try {
              request_param = select[i].getAttribute ("request-param");
              if (request_param == null ||
                    request_param.trim().equals ("")) {
                  continue;
              }
            } catch (Exception e) {
              continue;
            }
  
            try {
              nullstr = select[i].getAttribute ("nullable");
  
              if (nullstr != null) nullstr = nullstr.trim ();
  
              if ("yes".equals (nullstr) || "true".equals (nullstr)) {
                  nullable = true;
              }
  
            } catch (Exception e1) {
            }
  
            /* if there is a request parameter name,
            * but not the value, we exit immediately do
            * that authorization fails authomatically */
            request_value = req.getParameter (request_param);
  
            if (request_value == null || request_value.trim().equals ("")) {
              // value is null
              if (!nullable) {
                  getLogger ().debug ("DBXMLAUTH: request-param " + 
request_param + " does not exist");
                  return null;
              }
            } else {
              queryBufferEnd.append 
(dbcol).append("='").append(request_value).append("']");
              first_constraint = false;
            }
          }
  
          if (!queryBufferEnd.toString ().trim ().equals (""))
            queryBuffer.append (queryBufferEnd);
  
          return queryBuffer.toString ();
      } catch (Exception e) {
          getLogger ().debug ("DBXMLAUTH: got exception: " + e);
          return null;
      }
    }
  
  
    private ResourceSet Authenticate( Configuration conf, Request req) throws 
Exception, XMLDBException {
  
       ResourceSet rs = null;
  
      String query = this.getAuthQuery (conf, req);
      if (query == null) {
        getLogger ().debug ("DBXMLAUTH: have not got query");
        req.setAttribute("message", "The authenticator is misconfigured");
        return null;
      }
      getLogger ().debug ("DBXMLAUTH: query is: " + query);
  
  
      Collection col = CreateConnection( conf );
  
      if ( col != null )
      {
        if ( col.isOpen() )
        {
  
          try
          {
            XPathQueryService service = (XPathQueryService) 
col.getService("XPathQueryService", "1.0");
  
            rs = service.query(query);
            ResourceIterator results = rs.getIterator();
  
            if (results.hasMoreResources() == false)
            {
                getLogger ().debug ("DBXMLAUTH: auth failed");
                return null;
            } else {
              getLogger ().debug ("DBXMLAUTH: auth OK");
              return rs;
            }
  
          } catch (XMLDBException e) {
  
            getLogger ().debug ("DBXMLAUTH: got exception: " + e);
            return null;
  
          } finally {
  
            // close col
            if (col != null) {
              try {
                col.close();
              } catch (Exception e) { /* ignore */ }
            }
            getLogger ().debug ("DBXMLAUTH: collection closed");
  
          }
  
        } else {
          getLogger ().debug ("DBXMLAUTH: error: collection closed !!");
        }
  
      } else {
        getLogger ().debug ("DBXMLAUTH: couldn't open a connection with DB");
  
      }
  
      return null;
    }
  
  
    private Collection CreateConnection( Configuration conf ) throws Exception, 
XMLDBException {
  
      Collection col = null;
  
      Configuration conn = conf.getChild ("connection");
  
      try {
  
        Class c = Class.forName( conn.getChild("driver").getValue() );
  
        Database database = (Database) c.newInstance();
        DatabaseManager.registerDatabase(database);
  
        col = DatabaseManager.getCollection( conn.getChild("base").getValue() );
  
      } catch (XMLDBException e) {
        getLogger ().debug ("DBXMLAUTH: Exception occured " + e.errorCode);
      }
  
      return col;
    }
  
    private HashMap propagateParameters (Configuration conf,  ResourceSet 
resultSet, Session session) {
  
        Configuration table = conf.getChild ("root");
        Configuration[] select = table.getChildren ("select");
        String dbcol, session_param, type;
        HashMap map = new HashMap();
  
        XObject xo;
        Node originalnode = null;
  
        try {
  
          ResourceIterator results = resultSet.getIterator();
  
          // Create an XObject to be used in Xpath query
          xo = new XObject();
  
          // Retrieve the next node
          XMLResource resource = (XMLResource) results.nextResource();
  
          originalnode = resource.getContentAsDOM();
  
        }
        catch (Exception e) {
          getLogger ().debug ("DBXMLAUTH: error creating XObject ");
        }
  
  
        try {
            for (int i = 0; i < select.length; i ++) {
              dbcol = select[i].getAttribute ("element");
              try {
                session_param = select[i].getAttribute ("to-session");
                if (session_param != null && !session_param.trim().equals (""))
                {
  
                    String s = "";
  
                    try {
                      // Use Xalan xpath parser to extract data
                      xo = XPathAPI.eval(originalnode, "/" + table.getAttribute 
("name") + "/" + select[i].getAttribute ("element") );
                      s = xo.toString();
                    }
                    catch (Exception e) {
                    }
  
                    /* propagate to session */
                    try {
                      type = select[i].getAttribute ("type");
                    } catch (Exception e) {
                      type = null;
                    }
  
                    if (type == null || "".equals (type.trim ())) {
                      type = "string";
                    }
                    Object o = null;
  
                    if ("string".equals (type)) {
                      o = s;
                    } else if ("long".equals (type)) {
                      Long l = Long.decode (s);
                      o = l;
                    } else if ("double".equals (type)) {
                      Double d = Double.valueOf (s);
                      o = d;
                    }
  
                    if (session != null) {
                      session.setAttribute (session_param, o);
                      getLogger ().debug ("DBXMLAUTH: propagating param " + 
session_param + "=" + s);
                    }
                    map.put (session_param, o);
                }
              } catch (Exception e) {
              }
            }
            return map;
        } catch (Exception e) {
            getLogger().debug("exception: ", e);
        }
        return null;
      }
  }
  
  
  
  1.1                  
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/acting/OraAddAction.java
  
  Index: OraAddAction.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
      [EMAIL PROTECTED]
  
   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  <[EMAIL PROTECTED]>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  package org.apache.cocoon.acting;
  
  import oracle.jdbc.OracleResultSet;
  import oracle.sql.BLOB;
  import oracle.sql.CLOB;
  import org.apache.avalon.excalibur.datasource.DataSourceComponent;
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.configuration.ConfigurationException;
  import org.apache.avalon.framework.parameters.Parameters;
  import org.apache.cocoon.Constants;
  import org.apache.cocoon.ProcessingException;
  import org.apache.cocoon.environment.ObjectModelHelper;
  import org.apache.cocoon.environment.Redirector;
  import org.apache.cocoon.environment.Request;
  import org.apache.cocoon.environment.SourceResolver;
  import org.apache.cocoon.generation.ImageDirectoryGenerator;
  
  import java.io.*;
  import java.sql.Connection;
  import java.sql.PreparedStatement;
  import java.sql.ResultSet;
  import java.sql.SQLException;
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.Map;
  
  /**
   * Add a record in a database.  This Action assumes that there is
   * only one table at a time to update.
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Berin Loritsch</a>
   * @version CVS $Id: OraAddAction.java,v 1.1 2002/10/18 14:04:27 haul Exp $
   */
  public class OraAddAction extends DatabaseAddAction {
      private static final Map selectLOBStatements = new HashMap();
  
      /**
       * Add a record to the database.  This action assumes that
       * the file referenced by the "descriptor" parameter conforms
       * to the AbstractDatabaseAction specifications.
       */
      public Map act(Redirector redirector, SourceResolver resolver, Map 
objectModel, String source, Parameters param) throws Exception {
          DataSourceComponent datasource = null;
          Connection conn = null;
          int currentIndex = 0;
  
          try {
              Configuration conf = 
this.getConfiguration(param.getParameter("descriptor", null));
              String query = this.getAddQuery(conf);
  
              datasource = this.getDataSource(conf);
              conn = datasource.getConnection();
              Request request = ObjectModelHelper.getRequest(objectModel);
  
              if (conn.getAutoCommit()) {
                  conn.setAutoCommit(false);
              }
  
              PreparedStatement statement = conn.prepareStatement(query);
              getLogger().info(query);
  
              Configuration[] keys = 
conf.getChild("table").getChild("keys").getChildren("key");
              Configuration[] values = 
conf.getChild("table").getChild("values").getChildren("value");
              currentIndex = 1;
  
              // Insert the keys into the query
              for (int i = 0; i < keys.length; i++) {
                  String mode = keys[i].getAttribute("mode", "automatic");
  
                  if ("manual".equals(mode)) {
                      String selectQuery = this.getSelectQuery(keys[i]);
  
                      ResultSet set = 
conn.createStatement().executeQuery(selectQuery);
                      set.next();
                      int value = set.getInt("maxid") + 1;
  
                      statement.setInt(currentIndex, value);
  
                      request.setAttribute(keys[i].getAttribute("param"), 
String.valueOf(value));
  
                      set.close();
                      set.getStatement().close();
                      currentIndex++;
                  } else if ("form".equals(mode)) {
                      String parameter = keys[i].getAttribute("param");
                      request.setAttribute(parameter, 
request.getParameter(parameter));
                      this.setColumn(statement, currentIndex, request, keys[i]);
                      currentIndex++;
                  }
              }
  
              // insert the values into the query
              for (int i = 0; i < values.length; i++) {
                  String type = values[i].getAttribute("type");
                  String parameter = values[i].getAttribute("param");
  
                  if (type.equals("image")) {
                      File binaryFile = (File) request.get(parameter);
                      Parameters iparam = new Parameters();
  
                      iparam.setParameter("image-size", 
String.valueOf(binaryFile.length()));
  
                      int [] dimensions = 
ImageDirectoryGenerator.getSize(binaryFile);
                      iparam.setParameter("image-width", 
String.valueOf(dimensions[0]));
                      iparam.setParameter("image-height", 
String.valueOf(dimensions[1]));
  
                      synchronized (this.files) {
                          this.files.put(binaryFile, param);
                      }
                  }
  
                  if (! this.isLargeObject(type)) {
                      this.setColumn(statement, currentIndex, request, 
values[i]);
                      currentIndex++;
                  }
              }
  
              statement.execute();
              statement.close();
  
              query = this.getSelectLOBQuery(conf);
  
              // Process the large objects if they exist
              if (query != null) {
                  PreparedStatement LOBstatement = conn.prepareStatement(query);
                  getLogger().info(query);
  
                  if (keys.length > 0) {
                      currentIndex = 1;
  
                      for (int i = 0; i < keys.length; i++) {
                          this.setColumn(LOBstatement, currentIndex, request, 
keys[i]);
                          currentIndex++;
                      }
                  }
  
                  OracleResultSet set = (OracleResultSet) 
LOBstatement.executeQuery();
  
                  if (set.next()) {
                      int index = 0;
  
                      for (int i = 0; i < values.length; i++) {
                          String type = values[i].getAttribute("type", "");
                          if (this.isLargeObject(type)) {
                              Object attr = 
request.get(values[i].getAttribute("param"));
                              int length = -1;
                              InputStream stream = null;
                              OutputStream output = null;
                              int bufSize = 1024;
  
                              index++;
  
                              if (type.equals("ascii")) {
                                  CLOB ascii = set.getCLOB(index);
  
                                  if (attr instanceof File) {
                                      File asciiFile = (File) attr;
                                      stream = new BufferedInputStream(new 
FileInputStream(asciiFile));
                                  } else {
                                      String asciiText = (String) attr;
                                      stream = new BufferedInputStream(new 
ByteArrayInputStream(asciiText.getBytes()));
                                  }
  
                                  output = new 
BufferedOutputStream(ascii.getAsciiOutputStream());
                                  bufSize = ascii.getBufferSize();
                              } else {
                                  BLOB binary = set.getBLOB(index);
                                  File binaryFile = (File) attr;
                                  stream = new BufferedInputStream(new 
FileInputStream(binaryFile));
                                  length = (int) binaryFile.length();
  
                                  output = new 
BufferedOutputStream(binary.getBinaryOutputStream());
                                  bufSize = binary.getBufferSize();
                              }
  
                              byte[] buffer = new byte[bufSize];
                              while ((length = stream.read(buffer)) != -1) {
                                  output.write(buffer, 0, length);
                              }
  
                              stream.close();
                              output.close();
                          }
                      }
                  }
  
                  set.close();
                  set.getStatement().close();
              }
  
              conn.commit();
          } catch (Exception e) {
              if (conn != null) {
                  try {
                      conn.rollback();
                  } catch (SQLException se) {
                      getLogger().debug("There was an error rolling back the 
transaction", se);
                  }
              }
  
              throw new ProcessingException("Could not add record :position = " 
+ (currentIndex - 1), e);
          } finally {
              if (conn != null) {
                  try {
                      conn.close();
                  } catch (SQLException sqe) {
                      getLogger().warn("There was an error closing the 
datasource", sqe);
                  }
              }
  
              if (datasource != null) this.dbselector.release(datasource);
          }
  
          return null;
      }
  
      /**
       * Get the String representation of the PreparedStatement.  This is
       * mapped to the Configuration object itself, so if it doesn't exist,
       * it will be created.
       */
      protected final String getAddQuery(Configuration conf) throws 
ConfigurationException {
          String query = null;
  
          synchronized (DatabaseAddAction.addStatements) {
              query = (String) DatabaseAddAction.addStatements.get(conf);
  
              if (query == null) {
                  Configuration table = conf.getChild("table");
                  Configuration[] values = 
table.getChild("values").getChildren("value");
                  Configuration[] keys = 
table.getChild("keys").getChildren("key");
  
                  StringBuffer queryBuffer = new StringBuffer("INSERT INTO ");
                  queryBuffer.append(table.getAttribute("name"));
                  queryBuffer.append(" (");
  
                  int numKeys = 0;
  
                  for (int i = 0; i < keys.length; i++) {
                      String mode = keys[i].getAttribute("mode", "automatic");
                      if (numKeys > 0) {
                          queryBuffer.append(", ");
                      }
  
                      queryBuffer.append(keys[i].getAttribute("dbcol"));
  
                      if ("manual".equals(mode)) {
                          this.setSelectQuery(table.getAttribute("name"), 
keys[i]);
                      }
  
                      numKeys++;
                  }
  
                  for (int i = 0; i < values.length; i++) {
                      if ((numKeys + i) > 0) {
                          queryBuffer.append(", ");
                      }
  
                      queryBuffer.append(values[i].getAttribute("dbcol"));
                  }
  
                  queryBuffer.append(") VALUES (");
  
                  numKeys = 0;
                  ArrayList sequences = new ArrayList();
  
                  for (int i = 0; i < keys.length; i++) {
                      if (numKeys > 0) queryBuffer.append(", ");
                      if ("automatic".equals(keys[i].getAttribute("mode", 
"automatic"))) {
                          String sequence = keys[i].getAttribute("sequence", 
"");
                          queryBuffer.append(sequence);
  
                          if (sequences.contains(sequence)) {
                              queryBuffer.append(".CURRVAL");
                          } else {
                              sequences.add(sequence);
                              queryBuffer.append(".NEXTVAL");
                          }
  
                          numKeys++;
                      } else {
                          queryBuffer.append("?");
                          numKeys++;
                      }
                  }
  
                  for (int i = 0; i < values.length; i++) {
                      if ((numKeys + i) > 0) {
                          queryBuffer.append(", ");
                      }
  
                      if (this.isLargeObject(values[i].getAttribute("type"))) {
                          if (values[i].getAttribute("type").equals("ascii")) {
                               queryBuffer.append("empty_clob()");
                          } else {
                               queryBuffer.append("empty_blob()");
                          }
                      } else {
                          queryBuffer.append("?");
                      }
                  }
  
                  queryBuffer.append(")");
  
                  query = queryBuffer.toString();
  
                  DatabaseAddAction.addStatements.put(conf, query);
              }
          }
  
          if ("".equals(query)) return null;
  
          return query;
      }
  
      /**
       * Get the String representation of the PreparedStatement.  This is
       * mapped to the Configuration object itself, so if it doesn't exist,
       * it will be created.
       */
      private final String getSelectLOBQuery (Configuration conf)
      throws ConfigurationException {
          String query = null;
  
          synchronized (OraAddAction.selectLOBStatements) {
              query = (String) OraAddAction.selectLOBStatements.get(conf);
  
              // executes only if query is null.
              if (query == null) {
                  StringBuffer queryBuffer = new StringBuffer("SELECT ");
                  Configuration table = conf.getChild("table");
                  Configuration[] values = 
table.getChild("values").getChildren("value");
                  Configuration[] keys = 
table.getChild("keys").getChildren("key");
                  int numLobs = 0;
  
                  // Add the values to the query
                  for (int i = 0; i < values.length; i++) {
                      if (this.isLargeObject(values[i].getAttribute("type"))) {
                          numLobs++;
  
                          if (numLobs > 1) {
                              queryBuffer.append(", ");
                          }
  
                          queryBuffer.append(values[i].getAttribute("dbcol"));
                      }
                  }
  
                  if (numLobs < 1) {
                      // if query is set to "", then the Action won't
                      // try to process it again.
                      query = "";
                      OraAddAction.selectLOBStatements.put(conf, query);
                      return null;
                  }
  
                  queryBuffer.append(" FROM 
").append(table.getAttribute("name"));
  
                  // Process the WHERE clause
                  if (keys.length > 0) {
                      queryBuffer.append(" WHERE ");
  
                      // Add the keys to the query
                      for (int i = 0; i < keys.length; i++) {
                          if (i > 0) {
                              queryBuffer.append(" AND ");
                          }
  
                          queryBuffer.append(keys[i].getAttribute("dbcol"));
                          queryBuffer.append(" = ?");
                      }
                  }
  
                  query = queryBuffer.toString().trim();
                  OraAddAction.selectLOBStatements.put(conf, query);
              }
          }
  
          if ("".equals(query)) return null;
  
          return query;
      }
  }
  
  
  
  1.1                  
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/acting/OraUpdateAction.java
  
  Index: OraUpdateAction.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
      [EMAIL PROTECTED]
  
   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  <[EMAIL PROTECTED]>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  package org.apache.cocoon.acting;
  
  /**
   * Update a record in a database.  This Action assumes that there is
   * only one table at a time to update.
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Berin Loritsch</a>
   * @version CVS $Id: OraUpdateAction.java,v 1.1 2002/10/18 14:04:27 haul Exp $
   */
  public class OraUpdateAction extends DatabaseUpdateAction {
  
  }
  
  
  
  1.1                  
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/acting/modular/DatabaseAction.java
  
  Index: DatabaseAction.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
      [EMAIL PROTECTED]
  
   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  <[EMAIL PROTECTED]>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  
  package org.apache.cocoon.acting.modular;
  
  import java.io.IOException;
  import java.io.InputStream;
  import java.lang.Class;
  import java.net.URL;
  import java.sql.Connection;
  import java.sql.PreparedStatement;
  import java.sql.Statement;
  import java.sql.ResultSet;
  import java.sql.SQLException;
  import java.sql.Timestamp;
  import java.util.ArrayList;
  import java.util.Iterator;
  import java.util.Map;
  import java.util.List;
  import java.util.LinkedList;
  import java.util.ListIterator;
  import java.util.Enumeration;
  import java.util.Collections;
  import java.util.Set;
  import java.util.SortedSet;
  import java.util.TreeSet;
  import java.io.IOException;
  
  import org.apache.avalon.framework.activity.Disposable;
  import org.apache.avalon.framework.component.Component;
  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.configuration.Configurable;
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.configuration.ConfigurationException;
  import org.apache.avalon.framework.configuration.DefaultConfiguration;
  import org.apache.avalon.framework.context.Context;
  import org.apache.avalon.framework.context.ContextException;
  import org.apache.avalon.framework.context.Contextualizable;
  import org.apache.avalon.framework.parameters.Parameters;
  import org.apache.avalon.framework.parameters.ParameterException;
  import org.apache.avalon.framework.thread.ThreadSafe;
  import org.apache.avalon.excalibur.component.RoleManager;
  import org.apache.avalon.excalibur.component.DefaultRoleManager;
  import org.apache.avalon.excalibur.datasource.DataSourceComponent;
  
  
  import org.apache.cocoon.Constants;
  import org.apache.cocoon.ProcessingException;
  import org.apache.cocoon.components.classloader.RepositoryClassLoader;
  import org.apache.cocoon.environment.Redirector;
  import org.apache.cocoon.environment.SourceResolver;
  import org.apache.cocoon.generation.ImageDirectoryGenerator;
  import org.apache.cocoon.util.ClassUtils;
  import org.apache.cocoon.util.HashMap;
  import org.apache.cocoon.util.JDBCTypeConversions;
  import org.apache.cocoon.selection.Selector;
  
  import org.apache.cocoon.acting.AbstractComplementaryConfigurableAction;
  import org.apache.cocoon.components.modules.database.AutoIncrementModule;
  import org.apache.cocoon.components.modules.input.InputModule;
  import org.apache.cocoon.components.modules.output.OutputModule;
  
  /**
   * Abstract action for common function needed by database actions.
   * The difference to the other Database*Actions is, that the actions
   * in this package use additional components ("modules") for reading
   * and writing parameters. In addition the descriptor format has
   * changed to accomodate the new features.
   *
   * <p>This action is heavily based upon the original DatabaseAddActions.</p>
   *
   * <p>Modes have to be configured in cocoon.xconf. Mode names from
   * descriptor.xml file are looked up in the component service. Default
   * mode names can only be set during action setup. </p>
   *
   * <p>The number of affected rows is returned to the sitemap with the
   * "row-count" parameter if at least one row was affected.</p>
  
   * <table>
   * <tr><td colspan="2">Configuration options (setup):</td></tr>
   * <tr><td>input            </td><td>default mode name for reading 
values</td></tr>
   * <tr><td>autoincrement    </td><td>default mode name for obtaining values 
from autoincrement columns</td></tr>
   * </table>
   *
   * <table>
   * <tr><td colspan="2">Configuration options (setup and per 
invocation):</td></tr>
   * <tr><td>throw-exception  </td><td>throw an exception when an error occurs 
(default: false)</td></tr>
   * <tr><td>descriptor       </td><td>file containing database 
description</td></tr>
   * <tr><td>table-set        </td><td>table-set name to work with         
</td></tr>
   * <tr><td>output           </td><td>mode name for writing values        
</td></tr>
   * </table>
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Christian Haul</a>
   * @version CVS $Id: DatabaseAction.java,v 1.1 2002/10/18 14:04:27 haul Exp $
   * @see org.apache.cocoon.components.modules.input
   * @see org.apache.cocoon.components.modules.output
   * @see org.apache.cocoon.components.modules.database
   */
  public abstract class DatabaseAction  extends 
AbstractComplementaryConfigurableAction implements Configurable, Disposable {
  
      // 
========================================================================
      // constants
      // 
========================================================================
  
      static final Integer MODE_AUTOINCR = new Integer( 0 );
      static final Integer MODE_OTHERS = new Integer( 1 );
      static final Integer MODE_OUTPUT = new Integer( 2 );
  
      static final String ATTRIBUTE_KEY = 
"org.apache.cocoon.action.modular.DatabaseAction.outputModeName";
  
      // These can be overidden from cocoon.xconf
      static final String inputHint = "request-param"; // default to request 
parameters
      static final String outputHint = "request-attr"; // default to request 
attributes
      static final String databaseHint = "manual"; // default to manual auto 
increments
  
      static final String INPUT_MODULE_SELECTOR = InputModule.ROLE + "Selector";
      static final String OUTPUT_MODULE_SELECTOR = OutputModule.ROLE + 
"Selector";
      static final String DATABASE_MODULE_SELECTOR = AutoIncrementModule.ROLE + 
"Selector";
  
  
      // 
========================================================================
      // instance vars
      // 
========================================================================
  
      protected ComponentSelector dbselector;
      protected Map defaultModeNames = new HashMap( 3 );
      protected final HashMap cachedQueryData = new HashMap();
  
  
      // 
========================================================================
      // inner helper classes
      // 
========================================================================
  
      /**
       * Structure that takes all processed data for one column.
       */
      protected class Column {
          boolean isKey = false;
          boolean isSet = false;
          boolean isAutoIncrement = false;
          String mode = null;
          Configuration modeConf = null;
          Configuration columnConf = null;
      }
  
  
      /**
       * Structure that takes all processed data for a table depending
       * on current default modes
       */
      protected class CacheHelper {
          /**
           * Generated query string
           */
          public String queryString = null;
          /**
           * if a set is used, column number which is used to determine
           * the number of rows to insert.
           */
          public int setMaster = -1;
          public boolean isSet = false;
          public int noOfKeys = 0;
          public Column[] columns = null;
  
          public CacheHelper( int cols ) {
              this(0,cols);
          }
  
          public CacheHelper( int keys, int cols ) {
              noOfKeys = keys;
              columns = new Column[cols];
              for ( int i=0; i<cols; i++ ) {
                  columns[i] = new Column();
              }
          }
      }
  
  
      /**
       * Structure that takes up both current mode types for database
       * operations and table configuration data. Used to access parsed
       * configuration data.
       */
      protected class LookUpKey {
          public Configuration tableConf = null;
          public Map modeTypes = null;
  
          public LookUpKey( Configuration tableConf, Map modeTypes ) {
              this.tableConf = tableConf;
              this.modeTypes = modeTypes;
          }
      }
  
  
  
      // set up default modes
      // <input/>
      // <output/>
      // <autoincrement/>
      //
      // all other modes need to be declared in cocoon.xconf
      // no need to declare them per action (anymore!)
      public void configure(Configuration conf) throws ConfigurationException {
          super.configure(conf);
          if (this.settings != null) {
              this.defaultModeNames.put(MODE_OTHERS,   (String) 
this.settings.get("input",  inputHint));
              this.defaultModeNames.put(MODE_OUTPUT,   (String) 
this.settings.get("output", outputHint));
              this.defaultModeNames.put(MODE_AUTOINCR, (String) 
this.settings.get("autoincrement", databaseHint));
          }
      }
  
      // 
========================================================================
      // Avalon methods
      // 
========================================================================
  
      /**
       * Compose the Actions so that we can select our databases.
       */
      public void compose(ComponentManager manager) throws ComponentException {
          this.dbselector = (ComponentSelector) 
manager.lookup(DataSourceComponent.ROLE + "Selector");
  
          super.compose(manager);
      }
  
  
      /**
       *  dispose
       */
      public void dispose() {
          this.manager.release(dbselector);
      }
  
  
      // 
========================================================================
      // protected utility methods
      // 
========================================================================
  
      /**
       * Get the Datasource we need.
       */
      protected DataSourceComponent getDataSource( Configuration conf, 
Parameters parameters )
          throws ComponentException {
  
          String sourceName = parameters.getParameter( "connection", (String) 
settings.get( "connection" ) );
          if ( sourceName == null ) {
              Configuration dsn = conf.getChild("connection");
              return (DataSourceComponent) 
this.dbselector.select(dsn.getValue(""));
          } else {
              if (getLogger().isDebugEnabled())
                  getLogger().debug("Using datasource: "+sourceName);
              return (DataSourceComponent) this.dbselector.select(sourceName);
          }
      }
  
      /**
       * Return whether a type is a Large Object (BLOB/CLOB).
       */
      protected final boolean isLargeObject (String type) {
          if ("ascii".equals(type)) return true;
          if ("binary".equals(type)) return true;
          if ("image".equals(type)) return true;
  
          return false;
      }
  
      /**
       * Store a key/value pair in the output attributes. We prefix the key
       * with the name of this class to prevent potential name collisions.
       */
      protected void setOutputAttribute(Map objectModel, String outputMode, 
String key, Object value) {
  
          ComponentSelector outputSelector = null;
          OutputModule output = null;
          try {
              outputSelector=(ComponentSelector) 
this.manager.lookup(OUTPUT_MODULE_SELECTOR);
              if (outputMode != null && outputSelector != null && 
outputSelector.hasComponent(outputMode)){
                  output = (OutputModule) outputSelector.select(outputMode);
              }
              output.setAttribute( null, objectModel, key, value );
          } catch (Exception e) {
                  if (getLogger().isWarnEnabled())
                      getLogger()
                          .warn( "Could not select output mode "
                                 + (String) outputMode
                                 + ":" + e.getMessage() );
          } finally {
              if (outputSelector != null) {
                  if (output != null)
                      outputSelector.release(output);
                  this.manager.release(outputSelector);
              }
           }
      }
  
  
  
      /**
       * Inserts a row or a set of rows into the given table based on the
       * request parameters
       *
       * @param table the table's configuration
       * @param conn the database connection
       * @param objectModel the objectModel
       */
      protected int processTable( Configuration table, Connection conn, Map 
objectModel,
                                   Map results, Map modeTypes )
          throws SQLException, ConfigurationException, Exception {
  
          PreparedStatement statement = null;
          int rows = 0;
          try {
              LookUpKey luk = new LookUpKey(table, modeTypes);
              CacheHelper queryData = null;
  
              if (getLogger().isDebugEnabled())
                  getLogger().debug("modeTypes : "+ modeTypes);
  
              // get cached data
              // synchronize complete block since we don't want 100s of threads
              // generating the same cached data set. In the long run all data
              // is cached anyways so this won't cost much.
              synchronized (this.cachedQueryData) {
                  queryData = (CacheHelper) this.cachedQueryData.get(luk,null);
                  if (queryData == null) {
                      queryData = this.getQuery( table, modeTypes, 
defaultModeNames );
                      this.cachedQueryData.put(luk,queryData);
                  }
              };
  
              if (getLogger().isDebugEnabled())
                  getLogger().debug("query: "+queryData.queryString);
              statement = conn.prepareStatement(queryData.queryString);
  
              Object[][] columnValues = this.getColumnValues( table, queryData, 
objectModel );
  
              int setLength = 1;
              if ( queryData.isSet ) {
                  if ( columnValues[ queryData.setMaster ] != null ) {
                      setLength = columnValues[ queryData.setMaster ].length;
                  } else {
                      setLength = 0;
                  }
              }
  
              for ( int rowIndex = 0; rowIndex < setLength; rowIndex++ ) {
                  if (getLogger().isDebugEnabled())
                      getLogger().debug( "====> row no. " + rowIndex );
                  rows += processRow( objectModel, conn, statement, (String) 
modeTypes.get(MODE_OUTPUT), table, queryData, columnValues, rowIndex, results );
              }
  
          } finally {
              try {
                  if (statement != null) {
                      statement.close();
                  }
              } catch (SQLException e) {}
          }
          return rows;
      }
  
  
      /**
       * Choose a mode configuration based on its name.
       * @param conf Configuration (i.e. a column's configuration) that might 
have
       * several children configurations named "mode".
       * @param type desired type (i.e. every mode has a type
       * attribute), find the first mode that has a compatible type.
       * Special mode "all" matches all queried types.
       * @return configuration that has desired type or type "all" or null.
       */
      protected Configuration getMode( Configuration conf, String type )
          throws ConfigurationException {
  
          String modeAll = "all";
          Configuration[] modes = conf.getChildren("mode");
          Configuration modeConfig = null;;
  
          for ( int i=0; i<modes.length; i++ ) {
              String modeType = modes[i].getAttribute("type", "others");
              if ( modeType.equals(type) || modeType.equals(modeAll)) {
                  if (getLogger().isDebugEnabled())
                      getLogger().debug("requested mode was \""+type+"\" 
returning \""+modeType+"\"");
                  modeConfig = modes[i];
                  break;
              };
          }
  
          return modeConfig;
      }
  
  
      /**
       * compose name for output a long the lines of "table.column"
       */
      protected String getOutputName ( Configuration tableConf, Configuration 
columnConf ) {
  
          return getOutputName( tableConf, columnConf, -1 );
      }
  
  
      /**
       * compose name for output a long the lines of "table.column[row]" or
       * "table.column" if rowIndex is -1.
       * If the section of the sitemap corresponding to the action contains
       * <append-table-name>false</append-table-name>
       * the name for output is "column[row]"
       * If the section of the sitemap corresponding to the action contains
       * <append-row>false</append-row>
       * the name for output is "column"
       */
      protected String getOutputName ( Configuration tableConf, Configuration 
columnConf, int rowIndex ) {
  
          if ( rowIndex != -1 && this.settings.containsKey("append-row") && 
               
(this.settings.get("append-row").toString().equalsIgnoreCase("false") || 
                
this.settings.get("append-row").toString().equalsIgnoreCase("0")) ) {
              rowIndex = -1;
          }
          if ( this.settings.containsKey("append-table-name") && 
               
(this.settings.get("append-table-name").toString().equalsIgnoreCase("false") || 
                
this.settings.get("append-table-name").toString().equalsIgnoreCase("0")) )
              {
                  return ( columnConf.getAttribute("name",null)
                           + ( rowIndex == -1 ? "" : "[" + rowIndex + "]" ) );
              }
          else
              {
                  return ( tableConf.getAttribute("alias", 
tableConf.getAttribute("name", null) )
                           + "." + columnConf.getAttribute("name",null)
                           + ( rowIndex == -1 ? "" : "[" + rowIndex + "]" ) );
              }
      }
  
  
      /*
       * Read all values for a column from an InputModule
       *
       * If the given column is an autoincrement column, an empty array
       * is returned, otherwise if it is part of a set, all available
       * values are fetched, or only the first one if it is not part of
       * a set.
       *
       */
      protected Object[] getColumnValue( Configuration tableConf, Column 
column, Map objectModel )
          throws ConfigurationException, ComponentException {
  
          if ( column.isAutoIncrement ) {
              return new Object[1];
          } else {
              Object[] values;
              String cname = getOutputName( tableConf, column.columnConf );
  
              // obtain input module and read values
              ComponentSelector inputSelector = null;
              InputModule input = null;
              try {
                  inputSelector=(ComponentSelector) 
this.manager.lookup(INPUT_MODULE_SELECTOR);
                  if (column.mode != null && inputSelector != null && 
inputSelector.hasComponent(column.mode)){
                      input = (InputModule) inputSelector.select(column.mode);
                  }
  
                  if ( column.isSet ){
                      if (getLogger().isDebugEnabled())
                          getLogger().debug( "Trying to set column " + cname +" 
from "+column.mode+" using getAttributeValues method");
                      values = input.getAttributeValues( cname, 
column.modeConf, objectModel );
                  } else {
                      if (getLogger().isDebugEnabled())
                          getLogger().debug( "Trying to set column " + cname +" 
from "+column.mode+" using getAttribute method");
                      values = new Object[1];
                      values[0] = input.getAttribute( cname, column.modeConf, 
objectModel );
                  }
  
                  if ( values != null ) {
                      for ( int i = 0; i < values.length; i++ ) {
                          if (getLogger().isDebugEnabled())
                              getLogger().debug( "Setting column " + cname + " 
[" + i + "] " + values[i] );
                      }
                  }
  
              } finally {
                  if (inputSelector != null) {
                      if (input != null)
                          inputSelector.release(input);
                      this.manager.release(inputSelector);
                  }
              }
  
              return values;
          }
      }
  
  
      /**
       * Setup parsed attribute configuration object
       */
      protected void fillModes ( Configuration[] conf, boolean isKey, Map 
defaultModeNames,
                                 Map modeTypes, CacheHelper set )
          throws ConfigurationException {
  
          String setMode = null;
          int setMaster = -1;
          String setMastersMode = null;
          boolean manyrows = false;
          int offset = ( isKey ? 0: set.noOfKeys);
  
          for ( int i = offset; i < conf.length + offset; i++ ) {
              if (getLogger().isDebugEnabled())
                  getLogger().debug("i="+i);
              set.columns[i].columnConf =  conf[ i - offset ];
              set.columns[i].isSet = false;
              set.columns[i].isKey = isKey;
              set.columns[i].isAutoIncrement = false;
              if ( isKey & this.honourAutoIncrement() ) 
                  set.columns[i].isAutoIncrement = 
set.columns[i].columnConf.getAttributeAsBoolean("autoincrement",false);
              
              set.columns[i].modeConf = getMode( set.columns[i].columnConf,
                                                 selectMode( 
set.columns[i].isAutoIncrement, modeTypes ) );
              set.columns[i].mode = ( set.columns[i].modeConf != null ?
                                      set.columns[i].modeConf.getAttribute( 
"name", selectMode( isKey, defaultModeNames ) ) :
                                      selectMode( isKey, defaultModeNames ) );
              // Determine set mode for a whole column ...
              setMode = set.columns[i].columnConf.getAttribute("set", null);  
// master vs slave vs null
              if ( setMode == null && set.columns[i].modeConf != null ) {
                  // ... or for each mode individually
                  setMode = set.columns[i].modeConf.getAttribute("set", null);
              }
              if ( setMode != null ) {
                  manyrows = true;
                  set.columns[i].isSet = true;
                  set.isSet = true;
                  if ( setMode.equals("master") ) {
                      set.setMaster = i;
                  }
              }
          }
      }
  
      /**
       * create a unique name using the getOutputName method and write
       * the value to the output module and the results map if present.
       *
       */
      protected void setOutput( Map objectModel, String outputMode, Map results,
                           Configuration table, Configuration column, int 
rowIndex, Object value ) {
  
          String param = this.getOutputName( table, column, rowIndex );
          if (getLogger().isDebugEnabled())
              getLogger().debug( "Setting column " + param + " to " + value );
          this.setOutputAttribute(objectModel, outputMode, param, value);
          if (results != null)
              results.put( param, String.valueOf( value ) );
      }
  
      /**
       * set a column in a statement using the appropriate JDBC setXXX method.
       *
       */
      protected void setColumn ( PreparedStatement statement, int position, 
Configuration entry, Object value ) throws Exception {
  
          JDBCTypeConversions.setColumn(statement, position, value, (Integer) 
JDBCTypeConversions.typeConstants.get(entry.getAttribute("type")));
      }
  
  
      /**
       * set a column in a statement using the appropriate JDBC setXXX
       * method and propagate the value to the output module and results
       * map if present. Effectively combines calls to setColumn and
       * setOutput.
       *
       */
      protected void setColumn ( Map objectModel, String outputMode, Map 
results,
                                 Configuration table, Configuration column, int 
rowIndex, 
                                 Object value, PreparedStatement statement, int 
position ) throws Exception {
  
          if (results!=null) this.setOutput( objectModel, outputMode, results, 
table, column, rowIndex, value );
          this.setColumn( statement, position, column, value );
      }
  
  
      // 
========================================================================
      // main method
      // 
========================================================================
  
  
      /**
       * Add a record to the database.  This action assumes that
       * the file referenced by the "descriptor" parameter conforms
       * to the AbstractDatabaseAction specifications.
       */
      public Map act( Redirector redirector, SourceResolver resolver, Map 
objectModel,
                      String source, Parameters param ) throws Exception {
  
          DataSourceComponent datasource = null;
          Connection conn = null;
          Map results = new HashMap();
          int rows = 0;
  
          // read global parameter settings
          boolean reloadable = Constants.DESCRIPTOR_RELOADABLE_DEFAULT;
  
          // call specific default modes apart from output mode are not 
supported
          // set request attribute
          String outputMode = param.getParameter("output", (String) 
defaultModeNames.get(MODE_OUTPUT));
  
          if (this.settings.containsKey("reloadable"))
              reloadable = Boolean.valueOf((String) 
this.settings.get("reloadable")).booleanValue();
  
          // read local parameter settings
          try {
              Configuration conf =
                  this.getConfiguration(param.getParameter("descriptor", 
(String) this.settings.get("descriptor")),
                                        resolver,
                                        
param.getParameterAsBoolean("reloadable",reloadable));
  
              // get database connection and try to turn off autocommit
              datasource = this.getDataSource(conf, param);
              conn = datasource.getConnection();
              if (conn.getAutoCommit() == true) {
                  try {
                      conn.setAutoCommit(false);
                  } catch (Exception ex) {
                      String tmp = 
param.getParameter("use-transactions",(String) 
this.settings.get("use-transactions",null));
                      if (tmp != null &&  (tmp.equalsIgnoreCase("no") || 
tmp.equalsIgnoreCase("false") || tmp.equalsIgnoreCase("0"))) {
                          if (getLogger().isErrorEnabled())
                              getLogger().error("This DB connection does not 
support transactions. If you want to risk your data's integrity by continuing 
nonetheless set parameter \"use-transactions\" to \"no\".");
                          throw ex;
                      }
                  }
              }
  
              // find tables to work with
              Configuration[] tables = conf.getChildren("table");
              String tablesetname = param.getParameter("table-set", (String) 
this.settings.get("table-set"));
              Map set_tables = null; // default to old behaviour
  
              Map modeTypes = null;
  
              if (tablesetname == null) {
                  modeTypes = new HashMap(6);
                  modeTypes.put( MODE_AUTOINCR, "autoincr" );
                  modeTypes.put( MODE_OTHERS, "others" );
                  modeTypes.put( MODE_OUTPUT, outputMode );
                  for (int i=0; i<tables.length; i++) {
                      rows += processTable( tables[i], conn, objectModel, 
results, modeTypes );
                  }
              } else {
                  // new set based behaviour
  
                  // create index for table names / aliases
                  Map tableIndex = new HashMap(2*tables.length);
                  String tableName = null;
                  Object result = null;
                  for (int i=0; i<tables.length; i++) {
                      tableName = 
tables[i].getAttribute("alias",tables[i].getAttribute("name",""));
                      result = tableIndex.put(tableName,new Integer(i));
                      if (result != null) {
                          throw new IOException("Duplicate table entry for 
"+tableName+" at positions "+result+" and "+i);
                      }
                  }
  
                  Configuration[] tablesets = conf.getChildren("table-set");
                  String setname = null;
                  boolean found = false;
  
                  // find tables contained in tableset
                  int j = 0;
                  for (j=0; j<tablesets.length; j++) {
                      setname = tablesets[j].getAttribute ("name", "");
                      if (tablesetname.trim().equals (setname.trim ())) {
                          found = true;
                          break;
                      }
                  }
                  if (!found) {
                      throw new IOException(" given set " + tablesetname + " 
does not exists in a description file.");
                  }
  
                  Configuration[] set = tablesets[j].getChildren("table");
  
                  for (int i=0; i<set.length; i++) {
                      // look for alternative mode types
                      modeTypes = new HashMap(6);
                      modeTypes.put( MODE_AUTOINCR, set[i].getAttribute( 
"autoincr-mode", "autoincr" ) );
                      modeTypes.put( MODE_OTHERS, set[i].getAttribute( 
"others-mode",   "others" ) );
                      modeTypes.put( MODE_OUTPUT, outputMode );
                      tableName=set[i].getAttribute("name","");
                      if (tableIndex.containsKey(tableName)) {
                          j = ((Integer)tableIndex.get(tableName)).intValue();
                          rows += processTable( tables[j], conn, objectModel, 
results, modeTypes );
                      } else {
                          throw new IOException(" given table " + tableName + " 
does not exists in a description file.");
                      }
                  }
              }
  
              if (conn.getAutoCommit()==false)
                  conn.commit();
  
              // obtain output mode module and rollback output
              ComponentSelector outputSelector = null;
              OutputModule output = null;
              try {
                  outputSelector=(ComponentSelector) 
this.manager.lookup(OUTPUT_MODULE_SELECTOR);
                  if (outputMode != null && outputSelector != null && 
outputSelector.hasComponent(outputMode)){
                      output = (OutputModule) outputSelector.select(outputMode);
                  }
                  output.commit( null, objectModel );
              } catch (Exception e) {
                  if (getLogger().isWarnEnabled())
                      getLogger()
                          .warn( "Could not select output mode "
                                 + (String) outputMode
                                 + ":" + e.getMessage() );
              } finally {
                  if (outputSelector != null) {
                      if (output != null)
                          outputSelector.release(output);
                      this.manager.release(outputSelector);
                  }
              }
  
          } catch (Exception e) {
              if ( conn != null ) {
                  try {
                      if (getLogger().isDebugEnabled()) {
                          getLogger().debug( "Rolling back transaction. Caused 
by " + e.getMessage() );
                          e.printStackTrace();
                      }
                      conn.rollback();
                      results = null;
  
                      // obtain output mode module and commit output
                      ComponentSelector outputSelector = null;
                      OutputModule output = null;
                      try {
                          outputSelector=(ComponentSelector) 
this.manager.lookup(OUTPUT_MODULE_SELECTOR);
                          if (outputMode != null && outputSelector != null && 
outputSelector.hasComponent(outputMode)){
                              output = (OutputModule) 
outputSelector.select(outputMode);
                          }
                          output.rollback( null, objectModel, e);
                      } catch (Exception e2) {
                          if (getLogger().isWarnEnabled())
                              getLogger()
                                  .warn( "Could not select output mode "
                                         + (String) outputMode
                                         + ":" + e2.getMessage() );
                      } finally {
                          if (outputSelector != null) {
                              if (output != null)
                                  outputSelector.release(output);
                              this.manager.release(outputSelector);
                          }
                      }
  
                  } catch (SQLException se) {
                      if (getLogger().isDebugEnabled())
                          getLogger().debug("There was an error rolling back 
the transaction", se);
                  }
              }
  
              //throw new ProcessingException("Could not add record :position = 
" + currentIndex, e);
  
              // don't throw an exception, an error has been signalled, that 
should suffice
  
              String throwException = (String) this.settings.get( 
"throw-exception",
                                                                  
param.getParameter( "throw-exception", null ) );
              if ( throwException != null &&
                   ( throwException.equalsIgnoreCase( "true" ) || 
throwException.equalsIgnoreCase( "yes" ) ) ) {
                  throw new ProcessingException("Could not add record",e);
              }
          } finally {
              if (conn != null) {
                  try {
                      conn.close();
                  } catch (SQLException sqe) {
                      getLogger().warn("There was an error closing the 
datasource", sqe);
                  }
              }
  
              if (datasource != null)
                  this.dbselector.release(datasource);
          }
          if (results != null) {
              if (rows>0) {
                  results.put("row-count",new Integer(rows));
              } else {
                  results = null;
              }
          } else {
              if (rows>0) {
                  results = new HashMap(1);
                  results.put("row-count",new Integer(rows));
              }
          }
  
          return results; // (results == null? results : 
Collections.unmodifiableMap(results));
      }
  
  
  
      // 
========================================================================
      // abstract methods
      // 
========================================================================
  
  
      /**
       * set all necessary ?s and execute the query
       * return number of rows processed
       *
       * This method is intended to be overridden by classes that
       * implement other operations e.g. delete
       */
      protected abstract int processRow( Map objectModel, Connection conn, 
PreparedStatement statement, String outputMode,
                                         Configuration table, CacheHelper 
queryData, Object[][] columnValues,
                                         int rowIndex, Map results )
          throws SQLException, ConfigurationException, Exception;
  
      /**
       * determine which mode to use as default mode
       *
       * This method is intended to be overridden by classes that
       * implement other operations e.g. delete
       */
      protected abstract String selectMode( boolean isAutoIncrement, Map modes 
);
  
  
      /**
       * determine whether autoincrement columns should be honoured by
       * this operation. This is usually snsible only for INSERTs.
       *
       * This method is intended to be overridden by classes that
       * implement other operations e.g. delete
       */
      protected abstract boolean honourAutoIncrement();
  
  
      /**
       * Fetch all values for all columns that are needed to do the
       * database operation.
       *
       * This method is intended to be overridden by classes that
       * implement other operations e.g. delete
       */
      abstract Object[][] getColumnValues( Configuration tableConf, CacheHelper 
queryData, Map objectModel )
          throws ConfigurationException, ComponentException;
  
      /**
       * Get the String representation of the PreparedStatement.  This is
       * mapped to the Configuration object itself, so if it doesn't exist,
       * it will be created.
       *
       * This method is intended to be overridden by classes that
       * implement other operations e.g. delete
       *
       * @param table the table's configuration object
       * @return the insert query as a string
       */
      protected abstract CacheHelper getQuery( Configuration table, Map 
modeTypes, Map defaultModeNames )
          throws ConfigurationException, ComponentException;
  
  }
  
  
  
  1.1                  
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/acting/modular/DatabaseAddAction.java
  
  Index: DatabaseAddAction.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
      [EMAIL PROTECTED]
  
   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  <[EMAIL PROTECTED]>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  
  package org.apache.cocoon.acting.modular;
  
  import java.util.Map;
  import java.sql.Connection;
  import java.sql.Statement;
  import java.sql.PreparedStatement;
  import java.sql.SQLException;
  import org.apache.cocoon.util.HashMap;
  
  import org.apache.avalon.framework.component.ComponentException;
  import org.apache.avalon.framework.component.ComponentSelector;
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.configuration.ConfigurationException;
  
  import org.apache.cocoon.components.modules.database.AutoIncrementModule;
  
  /**
   * Adds record in a database. The action can update one or more
   * tables, and can add more than one row to a table at a time. See
   * [EMAIL PROTECTED] DatabaseAction} for details.
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Christian Haul</a>
   * @version CVS $Id: DatabaseAddAction.java,v 1.1 2002/10/18 14:04:27 haul 
Exp $
   */
  public class DatabaseAddAction extends DatabaseAction {
  
  
      /**
       * set all necessary ?s and execute the query
       */
      protected int processRow ( Map objectModel, Connection conn, 
PreparedStatement statement, String outputMode,
                                 Configuration table, CacheHelper queryData, 
Object[][] columnValues,
                                 int rowIndex, Map results )
          throws SQLException, ConfigurationException, Exception {
  
          int currentIndex = 1;
          for (int i = 0; i < queryData.columns.length; i++) {
              Column col = queryData.columns[i];
              if ( col.isAutoIncrement && col.isKey ) {
                  currentIndex += setKeyAuto( table, col, currentIndex, 
rowIndex,
                                              conn, statement, objectModel, 
outputMode, results );
              } else {
                  this.setOutput( objectModel, outputMode, results, table, 
col.columnConf, rowIndex,
                                  columnValues[ i ][ ( col.isSet ? rowIndex : 0 
) ]);
                  this.setColumn( statement, currentIndex, col.columnConf, 
                                  columnValues[ i ][ ( col.isSet ? rowIndex : 0 
) ]);
                  currentIndex++;
              }
          }
          int rowCount = statement.executeUpdate();
          // get resulting ids for autoincrement columns
          for (int i = 0; i < queryData.columns.length; i++) {
              if ( queryData.columns[i].isAutoIncrement && 
queryData.columns[i].isKey ) {
                  storeKeyValue( table, queryData.columns[i], rowIndex,
                                 conn, statement, objectModel, outputMode, 
results );
              }
          }
          return rowCount;
      }
  
  
      /**
       * Sets the key value on the prepared statement for an autoincrement type.
       *
       * @param table the table's configuration object
       * @param column the key's configuration object
       * @param currentIndex the position of the key column
       * @param rowIndex the position in the current row set
       * @param conn the database connection
       * @param statement the insert statement
       * @param objectModel the objectModel object
       * @param outputMode name of the requested output module
       * @param result sitemap result object
       * @return the number of columns by which to increment the currentIndex
       */
      protected int setKeyAuto ( Configuration table, Column column, int 
currentIndex, int rowIndex,
                                 Connection conn, PreparedStatement statement, 
Map objectModel, String outputMode, Map results )
          throws ConfigurationException, SQLException, ComponentException, 
Exception {
  
          int columnCount = 0;
          ComponentSelector autoincrSelector = null;
          AutoIncrementModule autoincr = null;
          try {
              autoincrSelector=(ComponentSelector) 
this.manager.lookup(DATABASE_MODULE_SELECTOR);
              if (column.mode != null && autoincrSelector != null && 
autoincrSelector.hasComponent(column.mode)){
                  autoincr = (AutoIncrementModule) 
autoincrSelector.select(column.mode);
              }
  
              if ( autoincr.includeInQuery() ) {
                  if ( autoincr.includeAsValue() ) {
                      Object value = autoincr.getPreValue( table, 
column.columnConf, column.modeConf, conn, objectModel );
                      this.setColumn(objectModel, outputMode, results, table, 
column.columnConf, rowIndex, value, statement, currentIndex);
                      columnCount = 1;
                  }
              } else {
                  if (getLogger().isDebugEnabled())
                      getLogger().debug( "Automatically setting key" );
              }
  
          } finally {
              if (autoincrSelector != null) {
                  if (autoincr != null)
                      autoincrSelector.release(autoincr);
                  this.manager.release(autoincrSelector);
              }
           }
  
          return columnCount;
      }
  
  
  
      /**
       * Put key values into request attributes. Checks whether the
       * value needs to be retrieved from the database module first.
       *
       */
      protected void storeKeyValue( Configuration tableConf, Column key, int 
rowIndex, Connection conn,
                                    Statement statement, Map objectModel, 
String outputMode, Map results )
          throws SQLException, ConfigurationException, ComponentException {
  
          ComponentSelector autoincrSelector = null;
          AutoIncrementModule autoincr = null;
          try {
              autoincrSelector=(ComponentSelector) 
this.manager.lookup(DATABASE_MODULE_SELECTOR);
              if (key.mode != null && autoincrSelector != null && 
autoincrSelector.hasComponent(key.mode)){
                  autoincr = (AutoIncrementModule) 
autoincrSelector.select(key.mode);
              }
  
              if (!autoincr.includeAsValue()) {
                  Object value = autoincr.getPostValue( tableConf, 
key.columnConf, key.modeConf, conn, statement, objectModel );
                  this.setOutput(objectModel, outputMode, results, tableConf, 
key.columnConf, rowIndex, value);
              }
  
          } finally {
              if (autoincrSelector != null) {
                  if (autoincr != null)
                      autoincrSelector.release(autoincr);
                  this.manager.release(autoincrSelector);
              }
           }
  
      }
  
  
      /**
       * determine which mode to use as default mode
       * here: INSERT
       * highly specific to operation INSERT / UPDATE / DELETE / SELECT
       */
      protected String selectMode ( boolean isAutoIncrement, Map modes ) {
  
          if ( isAutoIncrement )
              return (String) modes.get( MODE_AUTOINCR );
          else
              return (String) modes.get( MODE_OTHERS );
      }
  
  
      /**
       * determine whether autoincrement columns should be honoured by
       * this operation. This is usually snsible only for INSERTs.
       */
      protected boolean honourAutoIncrement() { return true; }
  
  
      /**
       * Fetch all values for all columns that are needed to do the
       * database operation.
       */
      protected Object[][] getColumnValues( Configuration tableConf, 
CacheHelper queryData,
                                            Map objectModel )
          throws ConfigurationException, ComponentException {
  
          Object[][] columnValues = new Object[ queryData.columns.length ][];
          for ( int i = 0; i < queryData.columns.length; i++ ){
              columnValues[i] = this.getColumnValue( tableConf, 
queryData.columns[i], objectModel );
          }
          return columnValues;
      }
  
  
      /**
       * Get the String representation of the PreparedStatement.  This is
       * mapped to the Configuration object itself, so if it doesn't exist,
       * it will be created.
       * @param table the table's configuration object
       * @return the insert query as a string
       */
      protected CacheHelper getQuery( Configuration table, Map modeTypes, Map 
defaultModeNames )
          throws ConfigurationException, ComponentException {
  
          LookUpKey lookUpKey = new LookUpKey( table, modeTypes );
          CacheHelper queryData = null;
          synchronized( this.cachedQueryData ) {
              queryData = (CacheHelper) this.cachedQueryData.get( lookUpKey );
  
              if (queryData == null) {
                  Configuration[] values = 
table.getChild("values").getChildren("value");
                  Configuration[] keys = 
table.getChild("keys").getChildren("key");
  
                  queryData = new CacheHelper( keys.length, keys.length + 
values.length );
                  fillModes( keys,   true,  defaultModeNames, modeTypes, 
queryData );
                  fillModes( values, false, defaultModeNames, modeTypes, 
queryData );
  
                  StringBuffer queryBuffer = new StringBuffer("INSERT INTO ");
                  StringBuffer valueBuffer = new StringBuffer(") VALUES (");
                  AutoIncrementModule dah;
  
                  queryBuffer.append(table.getAttribute("name"));
                  queryBuffer.append(" (");
                  int actualColumns = 0;
  
                  for (int i = 0; i < queryData.columns.length; i++) {
                      if ( actualColumns > 0 ) {
                          queryBuffer.append( ", " );
                          valueBuffer.append( ", " );
                      }
                      if ( queryData.columns[i].isKey && 
queryData.columns[i].isAutoIncrement ) {
  
                          ComponentSelector autoincrSelector = null;
                          AutoIncrementModule autoincr = null;
                          try {
                              autoincrSelector=(ComponentSelector) 
this.manager.lookup(DATABASE_MODULE_SELECTOR); 
                              if (queryData.columns[i].mode != null && 
autoincrSelector != null && 
autoincrSelector.hasComponent(queryData.columns[i].mode)){
                                  autoincr = (AutoIncrementModule) 
autoincrSelector.select(queryData.columns[i].mode);
                                  
                                  if ( autoincr.includeInQuery() ) {
                                      actualColumns++;
                                      queryBuffer.append( 
queryData.columns[i].columnConf.getAttribute( "name" ) );
                                      if ( autoincr.includeAsValue() ) {
                                          valueBuffer.append( "?" );
                                      } else {
                                          valueBuffer.append(
                                                             
autoincr.getSubquery( table, queryData.columns[i].columnConf,
                                                                                
   queryData.columns[i].modeConf ) );
                                      }
                                  }
                              } else {
                                  if (getLogger().isErrorEnabled())
                                      getLogger().error("Could not find mode 
description " 
                                                        + 
queryData.columns[i].mode + " for column #"+i);
                                  if (getLogger().isDebugEnabled()) {
                                      getLogger().debug("Column data 
"+queryData.columns[i]);
                                  }
                                  throw new ConfigurationException("Could not 
find mode description "+queryData.columns[i].mode+" for column "+i);
                              }
                              
                          } finally {
                              if (autoincrSelector != null) {
                                  if (autoincr != null) 
                                      autoincrSelector.release(autoincr);
                                  this.manager.release(autoincrSelector);
                              }
                          }
  
                      } else {
                          actualColumns++;
                          queryBuffer.append( 
queryData.columns[i].columnConf.getAttribute( "name" ) );
                          valueBuffer.append( "?" );
                      }
                  }
  
                  valueBuffer.append(")");
                  queryBuffer.append(valueBuffer);
  
                  queryData.queryString = queryBuffer.toString();
  
                  this.cachedQueryData.put( lookUpKey, queryData );
              }
          }
  
          return queryData;
      }
  
  
  }
  
  
  
  1.1                  
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/acting/modular/DatabaseDeleteAction.java
  
  Index: DatabaseDeleteAction.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
      [EMAIL PROTECTED]
  
   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  <[EMAIL PROTECTED]>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  
  package org.apache.cocoon.acting.modular;
  
  import java.util.Map;
  import java.sql.Connection;
  import java.sql.PreparedStatement;
  import java.sql.SQLException;
  import org.apache.cocoon.util.HashMap;
  
  import org.apache.avalon.framework.component.ComponentException;
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.configuration.ConfigurationException;
  
  /**
   * Updates a record in a database. The action can update one or more
   * tables, and can update more than one row to a table at a time. 
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Christian Haul</a>
   * @version CVS $Id: DatabaseDeleteAction.java,v 1.1 2002/10/18 14:04:27 haul 
Exp $
   */
  public class DatabaseDeleteAction extends DatabaseAction {
  
      /**
       * determine which mode to use as default mode
       * here: DELETE
       * highly specific to operation INSERT / UPDATE / DELETE / SELECT
       */
      protected String selectMode ( boolean isAutoIncrement, Map modes ) {
  
          return (String) modes.get( MODE_OTHERS );
      }
  
  
      /**
       * determine whether autoincrement columns should be honoured by
       * this operation. This is usually snsible only for INSERTs.
       */
      protected boolean honourAutoIncrement() { return false; }
  
  
      /**
       * Fetch all values for all key columns that are needed to do the
       * database operation.
       */
      protected Object[][] getColumnValues( Configuration tableConf, 
CacheHelper queryData, Map objectModel )
          throws ConfigurationException, ComponentException {
  
          Object[][] columnValues = new Object[ queryData.columns.length ][];
          for ( int i = 0; i < queryData.columns.length; i++ ){
              if ( queryData.columns[i].isKey ) {
                  columnValues[i] = this.getColumnValue( tableConf, 
queryData.columns[i], objectModel );
              } else {
                  // columnValues[i] = new Object[1]; // this should not be 
needed
              }
          }
          return columnValues;
      }
  
  
  
      /**
       * Get the String representation of the PreparedStatement.  This is
       * mapped to the Configuration object itself, so if it doesn't exist,
       * it will be created.
       *
       * @param table the table's configuration object
       * @return the insert query as a string
       */
      protected CacheHelper getQuery( Configuration table, Map modeTypes, Map 
defaultModeNames )
          throws ConfigurationException, ComponentException {
  
          LookUpKey lookUpKey = new LookUpKey( table, modeTypes );
          CacheHelper queryData = null;
          synchronized( this.cachedQueryData ) {
              queryData = (CacheHelper) this.cachedQueryData.get( lookUpKey );
              if (queryData == null) {
                  Configuration[] keys = 
table.getChild("keys").getChildren("key");
  
                  queryData = new CacheHelper( keys.length, keys.length );
                  fillModes( keys, true, defaultModeNames, modeTypes, queryData 
);
  
                  StringBuffer queryBuffer = new StringBuffer("DELETE FROM ");
                  queryBuffer.append(table.getAttribute("name")).append(" WHERE 
");
                  for (int i = 0; i < queryData.columns.length; i++) {
                      if ( i > 0 ) {
                          queryBuffer.append(" AND ");
                      }
                      queryBuffer
                          .append( 
queryData.columns[i].columnConf.getAttribute( "name" ) )
                          .append( "= ?" );
                  }
  
                  queryData.queryString = queryBuffer.toString();
  
                  this.cachedQueryData.put( lookUpKey, queryData );
              }
          }
  
          return queryData;
      }
  
  
  
      /**
       * set all necessary ?s and execute the query
       */
      protected int processRow ( Map objectModel, Connection conn, 
PreparedStatement statement, String outputMode,
                                 Configuration table, CacheHelper queryData, 
Object[][] columnValues,
                                 int rowIndex, Map results )
          throws SQLException, ConfigurationException, Exception {
  
          int currentIndex = 1;
  
          // ordering is different for DELETE just needs keys
          for (int i = 0; i < queryData.columns.length; i++) {
              Column col = queryData.columns[i];
              if ( col.isKey ) {
                  this.setColumn( objectModel, outputMode, results, table, 
col.columnConf, rowIndex,
                                  columnValues[ i ][ ( col.isSet ? rowIndex : 0 
) ], 
                                  statement, currentIndex );
                  currentIndex++;
              }
          }
          int rowCount = statement.executeUpdate();
          return rowCount;
      }
  
  }
  
  
  
  1.1                  
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/acting/modular/DatabaseQueryAction.java
  
  Index: DatabaseQueryAction.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
      [EMAIL PROTECTED]
  
   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  <[EMAIL PROTECTED]>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  
  package org.apache.cocoon.acting.modular;
  
  import java.util.Map;
  import java.sql.Connection;
  import java.sql.Clob;
  import java.sql.PreparedStatement;
  import java.sql.ResultSet;
  import java.sql.ResultSetMetaData;
  import java.sql.SQLException;
  import java.sql.Struct;
  import java.sql.Types;
  
  import java.io.InputStream;
  import java.io.BufferedInputStream;
  
  import org.apache.cocoon.util.HashMap;
  
  import org.apache.avalon.framework.component.ComponentException;
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.configuration.ConfigurationException;
  
  import org.apache.cocoon.util.JDBCTypeConversions;
  
  /**
   * Executes an arbitrary query. The query is associated with a table
   * and selected through the others mode. All keys and values are set
   * in order of appearance, starting with keys, thus the query needs to
   * have as many placeholders for prepared statement parameters. If it
   * is an update query, the number of affected rows is returned to the
   * sitemap.
   *
   *<pre>
   * &lt;table name="example"&gt;
   *   &lt;queries&gt;
   *      &lt;query mode="one"&gt;update example set count=count+1 where 
id=?&lt;/query&gt;
   *      &lt;query mode="two"&gt;select count, name from example where 
id=?&lt;/query&gt;
   *   &lt;/queries&gt;
   *   &lt;keys&gt;
   *     &lt;key name="id"/&gt;
   *   &lt;/keys&gt;
   *   &lt;values/&gt;
   * &lt;/table&gt;
   *</pre>
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Christian Haul</a>
   * @version CVS $Id: DatabaseQueryAction.java,v 1.1 2002/10/18 14:04:27 haul 
Exp $
   */
  public class DatabaseQueryAction extends DatabaseAction {
  
      /**
       * determine which mode to use as default mode
       * here: SELECT
       * highly specific to operation INSERT / UPDATE / DELETE / SELECT
       */
      protected String selectMode ( boolean isAutoIncrement, Map modes ) {
          
          return (String) modes.get( MODE_OTHERS );
      }
  
      /**
       * determine whether autoincrement columns should be honoured by
       * this operation. This is usually snsible only for INSERTs.
       */
      protected boolean honourAutoIncrement() { return false; }
  
  
      /**
       * Get the String representation of the PreparedStatement.  This is
       * mapped to the Configuration object itself, so if it doesn't exist,
       * it will be created.
       *
       * @param table the table's configuration object
       * @return the insert query as a string
       */
      protected CacheHelper getQuery( Configuration table, Map modeTypes, Map 
defaultModeNames )
          throws ConfigurationException, ComponentException {
  
          LookUpKey lookUpKey = new LookUpKey( table, modeTypes );
          CacheHelper queryData = null;
          synchronized( this.cachedQueryData ) {
              queryData = (CacheHelper) this.cachedQueryData.get( lookUpKey );
              if (queryData == null) {
                  Configuration[] queries = 
table.getChild("queries").getChildren("query");
                  Configuration[] keys = 
table.getChild("keys").getChildren("key");
                  Configuration[] values = 
table.getChild("values").getChildren("value");
  
                  boolean found = false;
                  String queryModeName = "";
                  String query = "";
                  boolean useValues = true;
                  for (int i=0; i<queries.length; i++) {
                      queryModeName = queries[i].getAttribute("mode",null);
                      if ( 
queryModeName.equals((String)modeTypes.get(MODE_OTHERS)) || 
"all".equals(queryModeName)) {
                          query = queries[i].getValue();
                          useValues = 
queries[i].getAttributeAsBoolean("use-values", useValues);
                          found = true;
                          break;
                      }
                  }
  
                  if (!found) {
                      throw new ConfigurationException("Could not find query 
mode " +
                                                       
modeTypes.get(MODE_OTHERS) + 
                                                       " for table " + 
table.getAttribute("name",null));
                  }
  
                  
  
                  queryData = new CacheHelper( keys.length, keys.length + 
(useValues ? values.length : 0));
                  queryData.queryString = query;
                  fillModes( keys  , true , defaultModeNames, modeTypes, 
queryData );
                  if (useValues) fillModes( values, false, defaultModeNames, 
modeTypes, queryData );
                  
                  this.cachedQueryData.put( lookUpKey, queryData );
              }
          }
  
          return queryData;
      }
  
  
      /**
       * Fetch all values for all columns that are needed to do the database 
operation.
       */
      protected Object[][] getColumnValues( Configuration tableConf, 
CacheHelper queryData, Map objectModel )
          throws ConfigurationException, ComponentException {
  
          Object[][] columnValues = new Object[ queryData.columns.length ][];
          for ( int i = 0; i < queryData.columns.length; i++ ){
              columnValues[i] = this.getColumnValue( tableConf, 
queryData.columns[i], objectModel );
          }
          return columnValues;
      }
  
  
      /**
       * set all necessary ?s and execute the query
       */
      protected int processRow ( Map objectModel, Connection conn, 
PreparedStatement statement, String outputMode,
                                 Configuration table, CacheHelper queryData, 
Object[][] columnValues, 
                                 int rowIndex, Map results )
          throws SQLException, ConfigurationException, Exception {
  
          int currentIndex = 1;
  
          // ordering is different for SELECT just needs keys
          for (int i = 0; i < queryData.columns.length; i++) {
              Column col = queryData.columns[i];
              if ( col.isKey ) {
                  this.setColumn(objectModel, outputMode, results, table, 
col.columnConf, rowIndex,
                                 columnValues[ i ][ ( col.isSet ? rowIndex : 0 
) ], statement, currentIndex );
                  currentIndex++;
              }
          }
          boolean hasResult = statement.execute();
          if (!hasResult) {
              return statement.getUpdateCount();
          } else {
              // retrieve values
              ResultSet resultset = statement.getResultSet();
              ResultSetMetaData metadata = resultset.getMetaData();
              rowIndex = 0;
              while ( resultset.next() ){
                  //if ( ! ( rowIndex == -1 && resultset.isLast() ) ) {
                  rowIndex++;
                  //}
                  String tableName = "";
                  String columnName = "";
                  for (int i = 1; i <= metadata.getColumnCount(); i++) {
                      Object value = resultset.getObject(i);
                      tableName = metadata.getTableName(i);
                      columnName = metadata.getColumnLabel(i) + 
"["+rowIndex+"]";
                      if (tableName != "") columnName = tableName + "." + 
columnName;
                      if (this.getLogger().isDebugEnabled())
                          this.getLogger().debug("retrieving "+columnName+" as 
"+value);
                      
results.put(metadata.getTableName(i)+"."+metadata.getColumnLabel(i),value);
                  }
              }
              return rowIndex;
          }
      }
  
  
  }
  
  
  
  1.1                  
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/acting/modular/DatabaseSelectAction.java
  
  Index: DatabaseSelectAction.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
      [EMAIL PROTECTED]
  
   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  <[EMAIL PROTECTED]>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  
  package org.apache.cocoon.acting.modular;
  
  import java.util.Map;
  import java.sql.Connection;
  import java.sql.Clob;
  import java.sql.PreparedStatement;
  import java.sql.ResultSet;
  import java.sql.SQLException;
  import java.sql.Struct;
  import java.sql.Types;
  
  import java.io.InputStream;
  import java.io.BufferedInputStream;
  
  import org.apache.cocoon.util.HashMap;
  
  import org.apache.avalon.framework.component.ComponentException;
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.configuration.ConfigurationException;
  
  import org.apache.cocoon.util.JDBCTypeConversions;
  
  /**
   * Selects a record from a database. The action can select one or more
   * tables, and can select from more than one row of a table at a
   * time.
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Christian Haul</a>
   * @version CVS $Id: DatabaseSelectAction.java,v 1.1 2002/10/18 14:04:27 haul 
Exp $
   */
  public class DatabaseSelectAction extends DatabaseAction {
  
      /**
       * determine which mode to use as default mode
       * here: SELECT
       * highly specific to operation INSERT / UPDATE / DELETE / SELECT
       */
      protected String selectMode ( boolean isAutoIncrement, Map modes ) {
          
          return (String) modes.get( MODE_OTHERS );
      }
  
  
      /**
       * determine whether autoincrement columns should be honoured by
       * this operation. This is usually snsible only for INSERTs.
       */
      protected boolean honourAutoIncrement() { return false; }
  
  
      /**
       * Get the String representation of the PreparedStatement.  This is
       * mapped to the Configuration object itself, so if it doesn't exist,
       * it will be created.
       *
       * @param table the table's configuration object
       * @return the insert query as a string
       */
      protected CacheHelper getQuery( Configuration table, Map modeTypes, Map 
defaultModeNames )
          throws ConfigurationException, ComponentException {
  
          LookUpKey lookUpKey = new LookUpKey( table, modeTypes );
          CacheHelper queryData = null;
          synchronized( this.cachedQueryData ) {
              queryData = (CacheHelper) this.cachedQueryData.get( lookUpKey );
              if (queryData == null) {
                  Configuration[] keys = 
table.getChild("keys").getChildren("key");
                  Configuration[] values = 
table.getChild("values").getChildren("value");
  
                  queryData = new CacheHelper( keys.length, keys.length + 
values.length );
                  fillModes( keys  , true , defaultModeNames, modeTypes, 
queryData );
                  fillModes( values, false, defaultModeNames, modeTypes, 
queryData );
                  
                  StringBuffer queryBuffer = new StringBuffer("SELECT ");
  
                  //queryBuffer.append(table.getAttribute("name")).append(" 
WHERE ");
                  int count = 0;
                  for (int i = 0; i < queryData.columns.length; i++) {
                      if ( !queryData.columns[i].isKey ) {
                          if ( count > 0 ) {
                              queryBuffer.append(", ");
                          }
                          queryBuffer
                              .append( 
queryData.columns[i].columnConf.getAttribute( "name" ) );
                          count++;
                      }
                  }
  
                  queryBuffer.append(" FROM 
").append(table.getAttribute("name")).append(" WHERE ");
                  count = 0;
                  for (int i = 0; i < queryData.columns.length; i++) {
                      if ( queryData.columns[i].isKey ) {
                          if ( count > 0 ) {
                              queryBuffer.append(" AND ");
                          }
                          queryBuffer
                              .append( 
queryData.columns[i].columnConf.getAttribute( "name" ) )
                              .append( "= ?");
                          count++;
                      }
                  }
  
                  queryData.queryString = queryBuffer.toString();
  
                  this.cachedQueryData.put( lookUpKey, queryData );
              }
          }
  
          return queryData;
      }
  
  
      /**
       * Fetch all values for all key columns that are needed to do the
       * database operation.
       */
      protected Object[][] getColumnValues( Configuration tableConf, 
CacheHelper queryData, Map objectModel )
          throws ConfigurationException, ComponentException {
  
          Object[][] columnValues = new Object[ queryData.columns.length ][];
          for ( int i = 0; i < queryData.columns.length; i++ ){
              if ( queryData.columns[i].isKey ) {
                  columnValues[i] = this.getColumnValue( tableConf, 
queryData.columns[i], objectModel );
              } else {
                  // columnValues[i] = new Object[1]; // this should not be 
needed
              }
          }
          return columnValues;
      }
  
  
      /**
       * set all necessary ?s and execute the query
       */
      protected int processRow ( Map objectModel, Connection conn, 
PreparedStatement statement, String outputMode,
                                 Configuration table, CacheHelper queryData, 
Object[][] columnValues, 
                                 int rowIndex, Map results )
          throws SQLException, ConfigurationException, Exception {
  
          int currentIndex = 1;
  
          // ordering is different for SELECT just needs keys
          for (int i = 0; i < queryData.columns.length; i++) {
              Column col = queryData.columns[i];
              if ( col.isKey ) {
                  this.setColumn(objectModel, outputMode, results, table, 
col.columnConf, rowIndex,
                                 columnValues[ i ][ ( col.isSet ? rowIndex : 0 
) ], statement, currentIndex );
                  currentIndex++;
              }
          }
          statement.execute();
          // retrieve values
          ResultSet resultset = statement.getResultSet();
          rowIndex = 0;
          while ( resultset.next() ){
              for (int i = 0; i < queryData.columns.length; i++) {
                  if ( !queryData.columns[i].isKey ) {
                      Object value = JDBCTypeConversions.getColumn( resultset, 
queryData.columns[i].columnConf );
                      this.setOutput(objectModel, outputMode, results, table, 
queryData.columns[i].columnConf, rowIndex, value);
                  }
              }
              rowIndex++;
          }
          if (rowIndex == 0) { results = EMPTY_MAP;}
          return rowIndex;
      }
  
  
  }
  
  
  
  1.1                  
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/acting/modular/DatabaseUpdateAction.java
  
  Index: DatabaseUpdateAction.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
      [EMAIL PROTECTED]
  
   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  <[EMAIL PROTECTED]>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  
  package org.apache.cocoon.acting.modular;
  
  import java.util.Map;
  import java.sql.Connection;
  import java.sql.PreparedStatement;
  import java.sql.SQLException;
  import org.apache.cocoon.util.HashMap;
  
  import org.apache.avalon.framework.component.ComponentException;
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.configuration.ConfigurationException;
  
  /**
   * Updates a record in a database. The action can update one or more
   * tables, and can update more than one row to a table at a time.
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Christian Haul</a>
   * @version CVS $Id: DatabaseUpdateAction.java,v 1.1 2002/10/18 14:04:27 haul 
Exp $
   */
  public class DatabaseUpdateAction extends DatabaseAction {
  
      /**
       * determine which mode to use as default mode
       * here: UPDATE
       * highly specific to operation INSERT / UPDATE / DELETE / SELECT
       */
      protected String selectMode ( boolean isAutoIncrement, Map modes ) {
  
          return (String) modes.get( MODE_OTHERS );
      }
  
  
      /**
       * determine whether autoincrement columns should be honoured by
       * this operation. This is usually snsible only for INSERTs.
       */
      protected boolean honourAutoIncrement() { return false; }
  
  
      /**
       * Fetch all values for all columns that are needed to do the
       * database operation.
       */
      protected Object[][] getColumnValues( Configuration tableConf, 
CacheHelper queryData, Map objectModel )
          throws ConfigurationException, ComponentException {
  
          Object[][] columnValues = new Object[ queryData.columns.length ][];
          for ( int i = 0; i < queryData.columns.length; i++ ){
              columnValues[i] = this.getColumnValue( tableConf, 
queryData.columns[i], objectModel );
          }
          return columnValues;
      }
  
  
      /**
       * Get the String representation of the PreparedStatement.  This is
       * mapped to the Configuration object itself, so if it doesn't exist,
       * it will be created.
       *
       * @param table the table's configuration object
       * @return the insert query as a string
       */
      protected CacheHelper getQuery( Configuration table, Map modeTypes, Map 
defaultModeNames )
          throws ConfigurationException, ComponentException {
  
          LookUpKey lookUpKey = new LookUpKey( table, modeTypes );
          CacheHelper queryData = null;
          synchronized( this.cachedQueryData ) {
              queryData = (CacheHelper) this.cachedQueryData.get( lookUpKey );
              if (queryData == null) {
                  Configuration[] keys = 
table.getChild("keys").getChildren("key");
                  Configuration[] values = 
table.getChild("values").getChildren("value");
  
                  queryData = new CacheHelper( keys.length, keys.length + 
values.length );
                  fillModes( keys,   true,  defaultModeNames, modeTypes, 
queryData );
                  fillModes( values, false, defaultModeNames, modeTypes, 
queryData );
  
                  StringBuffer queryBuffer = new StringBuffer("UPDATE ");
                  queryBuffer.append(table.getAttribute("name")).append(" SET 
");
  
  
                  int cols = 0;
                  for (int i = 0; i < queryData.columns.length; i++) {
                      if ( !queryData.columns[i].isKey ) {
                          if ( cols > 0 ) {
                              queryBuffer.append(", ");
                          }
                          cols++;
                          queryBuffer
                              .append( 
queryData.columns[i].columnConf.getAttribute( "name" ) )
                              .append( "= ?" );
                      }
                  }
                  queryBuffer.append(" WHERE ");
                  for (int i = 0; i < queryData.columns.length; i++) {
                      if ( queryData.columns[i].isKey ) {
                          if ( i > 0 ) {
                              queryBuffer.append(" AND ");
                          }
                          queryBuffer
                              .append( 
queryData.columns[i].columnConf.getAttribute( "name" ) )
                              .append( "= ?" );
                      }
                  }
  
                  queryData.queryString = queryBuffer.toString();
  
                  this.cachedQueryData.put( lookUpKey, queryData );
              }
          }
  
          return queryData;
      }
  
  
      /**
       * set all necessary ?s and execute the query
       */
      protected int processRow ( Map objectModel, Connection conn, 
PreparedStatement statement, String outputMode,
                                 Configuration table, CacheHelper queryData, 
Object[][] columnValues, 
                                 int rowIndex, Map results )
          throws SQLException, ConfigurationException, Exception {
  
  
          int currentIndex = 1;
  
          // ordering is different for UPDATE than for INSERT: values, keys
          for (int i = 0; i < queryData.columns.length; i++) {
              Column col = queryData.columns[i];
              if ( !col.isKey ) {
                  this.setColumn( objectModel, outputMode, results, table, 
col.columnConf, rowIndex,
                                  columnValues[ i ][ ( col.isSet ? rowIndex : 0 
) ], statement, currentIndex );
                  currentIndex++;
              }
          }
          for (int i = 0; i < queryData.columns.length; i++) {
              Column col = queryData.columns[i];
              if ( col.isKey ) {
                  this.setColumn( objectModel, outputMode, results, table, 
col.columnConf, rowIndex,
                                  columnValues[ i ][ ( col.isSet ? rowIndex : 0 
) ], statement, currentIndex );
                  currentIndex++;
              }
          }
          int rowCount = statement.executeUpdate();
          return rowCount;
      }
  
  }
  
  
  
  1.1                  
xml-cocoon2/src/blocks/databases/java/org/apache/cocoon/acting/modular/package.html
  
  Index: package.html
  ===================================================================
  <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
  <html>
  <head>
    <title>modular</title>
               
    <meta http-equiv="content-type"
   content="text/html; charset=ISO-8859-1">
  </head>
  <body>
     
  <h1>modular</h1>
  <p>These sitemap components use modules to obtain values and are thus very
  flexible in use.<br>
  </p>
    
  </body>
  </html>
  
  
  
  1.1                  
xml-cocoon2/src/blocks/databases/conf/databases-trans.xmap
  
  Index: databases-trans.xmap
  ===================================================================
  <?xml version="1.0"?>
  
  <xmap xpath="/sitemap/components/transformers" unless="[EMAIL 
PROTECTED]'sql']">
  
     <map:transformer logger="sitemap.transformer.sql" name="sql" 
src="org.apache.cocoon.transformation.SQLTransformer"/>
  
  </xmap>
  
  
  1.1                  xml-cocoon2/src/blocks/databases/conf/datasources.xconf
  
  Index: datasources.xconf
  ===================================================================
  <?xml version="1.0"?>
  
  <xconf xpath="/cocoon/datasources" unless="[EMAIL PROTECTED]'personnel']">
      <jdbc logger="core.datasources.personnel" name="personnel">
        <!--
            If you have an Oracle database, and are using the the
        pool-controller below, you should add the attribute
        "oradb" and set it to true.
  
        <pool-controller min="5" max="10" oradb="true"/>
  
        That way the test to see if the server has disconnected
        the JdbcConnection will function properly.
        -->
        <pool-controller max="10" min="5"/>
        <!--
            If you need to ensure an autocommit is set to true or
        false, then create the "auto-commit" element below.
  
        <auto-commit>false</auto-commit>
  
        The default is true.
        -->
        <dburl>@db_url@</dburl>
        <user>@db_user@</user>
        <password>@db_password@</password>
      </jdbc>
  </xconf>
  
  
  1.1                  
xml-cocoon2/src/blocks/databases/conf/db-modules-input.xconf
  
  Index: db-modules-input.xconf
  ===================================================================
  <?xml version="1.0"?>
  
  <xconf xpath="/cocoon/input-modules" unless="[EMAIL 
PROTECTED]'org.apache.cocoon.components.modules.input.CollectionMetaModule']">
  
        <component-instance logger="core.modules.input" name="collection"       
class="org.apache.cocoon.components.modules.input.CollectionMetaModule"/>
  
  </xconf>
  
  
  1.1                  xml-cocoon2/src/blocks/databases/conf/db-modules.xconf
  
  Index: db-modules.xconf
  ===================================================================
  <?xml version="1.0"?>
  
  <xconf xpath="/cocoon" unless="autoincrement-modules">
     <!-- =============== Database Modules ==================== -->
     
     <autoincrement-modules>
        <component-instance logger="core.modules.auto" name="auto" 
class="org.apache.cocoon.components.modules.database.HsqlIdentityAutoIncrementModule"/>
  <!--
        Choose the one suitable for your DBMS. You *can* have more than
        one at a time, but they need to have different names. You then
        need to specify explicitly, which one to use in your descriptor
        file.
  
        <component-instance logger="core.modules.auto" name="auto" 
class="org.apache.cocoon.components.modules.database.ManualAutoIncrementModule"/>
        <component-instance logger="core.modules.auto" name="auto" 
class="org.apache.cocoon.components.modules.database.IfxSerialAutoIncrementModule"/>
        <component-instance logger="core.modules.auto" name="auto" 
class="org.apache.cocoon.components.modules.database.MysqlAutoIncrementModule"/>
  -->
     </autoincrement-modules>
  </xconf>
  
  
  1.1                  xml-cocoon2/src/blocks/databases/conf/db-modules.xroles
  
  Index: db-modules.xroles
  ===================================================================
  <?xml version="1.0"?>
  <xroles xpath="/role-list" unless="[EMAIL 
PROTECTED]'org.apache.cocoon.components.modules.database.AutoIncrementModuleSelector']">
    <!-- database modules -->
  
    <role 
name="org.apache.cocoon.components.modules.database.AutoIncrementModuleSelector"
          shorthand="autoincrement-modules"
          
default-class="org.apache.avalon.excalibur.component.ExcaliburComponentSelector"/>
  
  </xroles>
  
  
  
  1.1                  xml-cocoon2/src/blocks/databases/conf/esql.xconf
  
  Index: esql.xconf
  ===================================================================
  <?xml version="1.0"?>
  
  <xconf xpath="/cocoon/markup-languages/[EMAIL PROTECTED]'xsp']/[EMAIL 
PROTECTED]'java']" unless="builtin-logicsheet/[EMAIL PROTECTED]'prefix' and 
@value='esql']">
  
          <!-- The ESQL logicsheet is an XSP logicsheet that performs sql 
queries and 
               serializes their results as XML. This allows you to work with 
data from a 
               wide variety of different sources when using Apache Cocoon. -->
          <builtin-logicsheet>
            <parameter name="prefix" value="esql"/>
            <parameter name="uri" value="http://apache.org/cocoon/SQL/v2"/>
            <parameter name="href" 
value="resource://org/apache/cocoon/components/language/markup/xsp/java/esql.xsl"/>
          </builtin-logicsheet>
  
  
  </xconf>
  
  

----------------------------------------------------------------------
In case of troubles, e-mail:     [EMAIL PROTECTED]
To unsubscribe, e-mail:          [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to