haul        01/11/23 02:50:36

  Modified:    webapp/WEB-INF/db cocoondb.properties cocoondb.script
               scratchpad/webapp/mount/mod-db database.xml edit-groups.xsp
                        schema.sql sitemap.xmap user-list.xsp
               scratchpad/src/org/apache/cocoon/acting
                        ModularDatabaseAddAction.java
                        ModularDatabaseDeleteAction.java
                        ModularDatabaseSelectAction.java
                        ModularDatabaseUpdateAction.java
               scratchpad/src/org/apache/cocoon/acting/ModularDatabaseAccess
                        AbstractAttributeHelper.java AttributeHelper.java
                        HsqlIdentityKeyAttributeHelper.java
                        IfxSerialKeyAttributeHelper.java
                        ManualKeyAttributeHelper.java OutputHelper.java
                        RequestAttributeHelper.java
                        RequestAttributeOutputHelper.java
                        RequestParameterHelper.java
  Added:       scratchpad/src/org/apache/cocoon/acting
                        ModularDatabaseAction.java
               scratchpad/src/org/apache/cocoon/acting/ModularDatabaseAccess
                        AbstractAutoIncrementHelper.java
                        AbstractOutputHelper.java AutoIncrementHelper.java
  Removed:     scratchpad/src/org/apache/cocoon/acting/ModularDatabaseAccess
                        AbstractKeyAttributeHelper.java AccessHelper.java
                        KeyAttributeHelper.java
  Log:
  Polished interfaces + some restructuring.
  Now open for review.
  
  Revision  Changes    Path
  1.5       +1 -1      xml-cocoon2/webapp/WEB-INF/db/cocoondb.properties
  
  Index: cocoondb.properties
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/webapp/WEB-INF/db/cocoondb.properties,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- cocoondb.properties       2001/11/19 16:06:33     1.4
  +++ cocoondb.properties       2001/11/23 10:50:35     1.5
  @@ -1,4 +1,4 @@
   #HSQL database
  -#Mon Nov 19 17:19:34 CET 2001
  +#Fri Nov 23 11:13:29 CET 2001
   version=1.6
   modified=no
  
  
  
  1.3       +3 -3      xml-cocoon2/webapp/WEB-INF/db/cocoondb.script
  
  Index: cocoondb.script
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/webapp/WEB-INF/db/cocoondb.script,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- cocoondb.script   2001/11/19 16:06:34     1.2
  +++ cocoondb.script   2001/11/23 10:50:35     1.3
  @@ -1,10 +1,10 @@
   CREATE TABLE DEPARTMENT_TABLE(ID INTEGER,NAME VARCHAR,UNIQUE(ID))
   CREATE TABLE EMPLOYEE_TABLE(ID INTEGER,DEPARTMENT_ID INTEGER,NAME 
VARCHAR,UNIQUE(ID))
  -CREATE TABLE USER(UID INTEGER IDENTITY PRIMARY KEY,NAME VARCHAR,SURNAME 
VARCHAR,UNAME VARCHAR,UNIQUE(UNAME))
  +CREATE TABLE USER(UID INTEGER IDENTITY PRIMARY KEY,NAME VARCHAR,FIRSTNAME 
VARCHAR,UNAME VARCHAR,UNIQUE(UNAME))
   CREATE TABLE GROUPS(GID INTEGER IDENTITY PRIMARY KEY,GNAME 
VARCHAR,UNIQUE(GNAME))
   CREATE TABLE USER_GROUPS(UID INTEGER,GID INTEGER,UNIQUE(UID,GID),FOREIGN 
KEY(UID)REFERENCES USER(UID),FOREIGN KEY(GID)REFERENCES GROUPS(GID))
  -GRANT ALL ON CLASS "java.lang.Math" TO PUBLIC
   GRANT ALL ON CLASS "org.hsqldb.Library" TO PUBLIC
  +GRANT ALL ON CLASS "java.lang.Math" TO PUBLIC
   CREATE USER SA PASSWORD "" ADMIN
   CREATE ALIAS DAYNAME FOR "org.hsqldb.Library.dayname"
   CREATE ALIAS SPACE FOR "org.hsqldb.Library.space"
  @@ -52,7 +52,7 @@
   CREATE ALIAS CURTIME FOR "org.hsqldb.Library.curtime"
   CREATE ALIAS DIFFERENCE FOR "org.hsqldb.Library.difference"
   CREATE ALIAS INSERT FOR "org.hsqldb.Library.insert"
  -CREATE ALIAS SUBSTR FOR "org.hsql.Library.substring"
  +CREATE ALIAS SUBSTR FOR "org.hsqldb.Library.substring"
   CREATE ALIAS DATABASE FOR "org.hsqldb.Library.database"
   CREATE ALIAS MINUTE FOR "org.hsqldb.Library.minute"
   CREATE ALIAS HOUR FOR "org.hsqldb.Library.hour"
  
  
  
  1.2       +38 -24    xml-cocoon2/scratchpad/webapp/mount/mod-db/database.xml
  
  Index: database.xml
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/scratchpad/webapp/mount/mod-db/database.xml,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- database.xml      2001/11/19 16:28:32     1.1
  +++ database.xml      2001/11/23 10:50:35     1.2
  @@ -9,35 +9,50 @@
           autoincrements work differently on different DBMSs, so we need
           special support to find out about the value set by the DBMS.
      -->
  -   <table name="user"><!-- @name is the table's name in the DB -->
  +   <table name="user" alias="user">
  +      <!-- @name is the table's name in the DB -->
  +      <!-- @alias is used instead (if present) for those weirdos that put -->
  +      <!-- complex queries into @name ;-) You obviously loose all but select 
-->
  +      <!-- functionality, although this is not enforced. -->
         <keys>
  -         <key name="uid" type="int">
  +         <key name="uid" type="int" autoincrement="true">
            <!-- @name is the column's name -->
            <!-- @type is the column's jdbc type -->
  -         <mode name="auto"  type="insert"/>
  +            <!-- @autoincrement : column value is determined by special 
component -->
  +         <mode name="auto"  type="autoincr"/>
            <!-- this entry says:
  -         when inserting a new column (@type="insert"), use the
  -         helper named "auto" to find out about how to handle this
  -         column. All other operations use the default mode. 
  -         There are two distinct mode types: "insert" for insert
  -         operations and "others" for all other (delete, update,
  -         select) -->
  +         when inserting a new column into a autoincrement column
  +            (@type="autoincr"), use the helper named "auto" to find out about
  +            how to handle this column. All other operations use the default
  +            mode.  
  +         There are two distinct mode types: "autoincr" for insert
  +         operations on autoincrement columns and "others" for all other
  +            (delete, update, select) operations on autoincrement columns and
  +            all operations on other columns. 
  +            -->
         </key>
         </keys>
         <values>
  -         <value name="name"    type="string"></value>
  -         <value name="surname" type="string"></value>
  -         <value name="uname"   type="string"></value>
  +         <value name="name"      type="string"></value>
  +         <value name="firstname" type="string"></value>
  +         <value name="uname"     type="string"></value>
         </values>   
      </table>
   
      <table name="user_groups">
         <keys>
            <key name="uid" type="int">
  -         <!-- Next we have two different modes: a default and
  +         <!-- Next we have two different modes: "request" and
            "attrib". See below for explanation. -->
            <mode name="request" parameter="user_groups.uid" type="request"/>
  -            <mode name="attribute" 
parameter="org.apache.cocoon.acting.ModularDatabaseAccess.OutputHelper:user.uid"
 type="attrib"/>
  +            <mode name="attribute" 
parameter="org.apache.cocoon.acting.ModularDatabaseAccess.OutputHelper:user.uid[0]"
 type="attrib"/>
  +         <!--  note here, that the actual parameter has a row index
  +         to it. We don't expect to insert more than one user plus
  +         her groups at any time, so we append just "[0]". However,
  +         if that would be the case, we could let this column be
  +         part of a set and ask for "[*]" instead. Might be tricky
  +         to find the associated groups, though, if we insert x
  +         users plus y_1, y_2, ... , y_x groups.... -->
         </key>
         <key name="gid" type="int" set="master">
            <!-- now, this is tricky: when we need to insert multiple
  @@ -47,7 +62,8 @@
            master is used to obtain a sorted set of index values for
            these rows. These will then be used to get the actual
            values for the master and slave columns. Note that it is
  -         not necessary to have the master be a key column. 
  +         not necessary to have the master be a key column. Note too, that an
  +            autoincrement column may not serve as a master here.
   
            This attribute may be specified on a column level or on a
            mode level to allow different behavious. Mode level @set
  @@ -61,12 +77,12 @@
   
      <table name="groups">
         <keys>
  -         <key name="gid" type="int">
  -         <mode name="auto"  type="insert"/>
  +         <key name="gid" type="int" autoincrement="true">
  +         <mode name="auto" type="autoincr"/>
         </key>
         </keys>
         <values>
  -         <value name="gname"   type="string"></value>
  +         <value name="gname" type="string"/>
         </values>   
      </table>
      
  @@ -88,21 +104,19 @@
   
      <table-set name="user+groups">
         <table name="user"/>
  -      <table name="user_groups" add-mode="attrib" others-mode="request"/>
  +      <table name="user_groups" others-mode="attrib"/>
         <!-- below we have another table set that inserts data into
         user_groups. When inserting into user_groups alone, we'd know
         the uid before hand, but when inserting a new user as well, we
         need to find out the autoincrement value first. Therefore we
         need a different approach to obtain that value. So we can
  -      instruct the action to use for add operations ("request") a
  -      different type (here "attrib") which reads the result from the
  -      first insert operation. We could as well specify a different
  -      mode for "others" operations as well: others-mode
  +      instruct the action to use a different type (here "attrib") which reads
  +      the result from the first insert operation. 
         -->
      </table-set>
   
      <table-set name="user_groups">
  -      <table name="user_groups" add-mode="request" others-mode="request"/>
  +      <table name="user_groups" others-mode="request"/>
      </table-set>
   
   </root>
  
  
  
  1.2       +210 -209  
xml-cocoon2/scratchpad/webapp/mount/mod-db/edit-groups.xsp
  
  Index: edit-groups.xsp
  ===================================================================
  RCS file: 
/home/cvs/xml-cocoon2/scratchpad/webapp/mount/mod-db/edit-groups.xsp,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- edit-groups.xsp   2001/11/19 16:28:32     1.1
  +++ edit-groups.xsp   2001/11/23 10:50:35     1.2
  @@ -5,229 +5,230 @@
             xmlns:xsp="http://apache.org/xsp";
          xmlns:esql="http://apache.org/cocoon/SQL/v2";
             xmlns:xsp-request="http://apache.org/xsp/request/2.0";
  ->
  -<!--
  --->
  -<xsp:structure>
  -   <xsp:include>java.util.Enumeration</xsp:include>
  -</xsp:structure>
  -
  -<page>
  -   <title>edit-groups</title>
  -
  +  >
  +  <!--
  +       -->
  +  <xsp:structure>
  +    <xsp:include>java.util.Enumeration</xsp:include>
  +  </xsp:structure>
  +  
  +  <page>
  +    <title>edit-groups</title>
  +    
   
  -  <esql:connection>
  -    <esql:pool>personnel</esql:pool>
  +    <esql:connection>
  +      <esql:pool>personnel</esql:pool>
       
  -    <xsp:logic>
  -      String user = <xsp-request:get-parameter name="user.uid"/>;
  -      if ( user == null ) {
  -         user = <xsp-request:get-parameter name="user_groups.uid"/>;
  -      }
  -      int uid=-1;
  -      if ( user != null ) {
  -        try {
  -          uid = Integer.parseInt(user);
  -        } catch ( NumberFormatException e ) {
  -          uid = -1;
  -        }
  -      }
  -      String uname="";
  -      String name="";
  -      String surname="";
  -      if ( uid != -1 ) {
  -        <esql:execute-query>
  -          <esql:query>select * from user where 
uid=<esql:parameter><xsp:expr>uid</xsp:expr></esql:parameter></esql:query>
  -          <esql:results>
  -            <esql:row-results>
  -              <xsp:logic>
  -                uid=<esql:get-int column="uid"/>;
  -                uname=<esql:get-string column="uname"/>;
  -             name=<esql:get-string column="name"/>;
  -             surname=<esql:get-string column="surname"/>;
  -           </xsp:logic>
  -            </esql:row-results>
  -          </esql:results>
  -        </esql:execute-query>
  -      }
  -    </xsp:logic>
  -
  -
  -<h1>Edit User's Groups</h1>
  -<table cellpadding="2" cellspacing="2" border="0">
  -  <tbody>
  -    <form>
  -    <tr>
  -      <td valign="Top" align="Right">uname
  -      </td>
  -      <td valign="Top">
  -         <input type="text" name="user.uname">
  -         <xsp:attribute 
name="value"><xsp:expr>uname</xsp:expr></xsp:attribute>
  -      </input>
  -      </td>
  -      <td>
  -      </td>
  -    </tr>
  -    <tr>
  -      <td valign="Top" align="Right">surname, name</td>
  -      <td>
  -         <input type="text" name="user.surname">
  -         <xsp:attribute 
name="value"><xsp:expr>surname</xsp:expr></xsp:attribute>
  -      </input>,
  -         <input type="text" name="user.name">
  -         <xsp:attribute 
name="value"><xsp:expr>name</xsp:expr></xsp:attribute>
  -      </input>
  -      </td>
  -      <td>
  -         <input type="hidden" name="user.uid">
  -         <xsp:attribute name="value"><xsp:expr>uid</xsp:expr></xsp:attribute>
  -      </input>
  -         <input type="submit" name="upd-user" value="update"/>
  -      </td>
  -    </tr>
  -    </form>
  -    <tr>
  -      <td valign="Top">
  -      </td>
  -      <td valign="Top" align="right">
  -      <form>
  -        <table border="1">
  -          <tbody>
  +      <xsp:logic>
  +         String user = <xsp-request:get-parameter name="user.uid"/>;
  +         if ( user == null ) {
  +            user = <xsp-request:get-parameter name="user_groups.uid"/>;
  +         }
  +         int uid=-1;
  +         if ( user != null ) {
  +           try {
  +             uid = Integer.parseInt(user);
  +           } catch ( NumberFormatException e ) {
  +             uid = -1;
  +           }
  +         }
  +         String uname="";
  +         String name="";
  +         String firstname="";
  +         if ( uid != -1 ) {
  +           <esql:execute-query>
  +             <esql:query>select * from user where 
uid=<esql:parameter><xsp:expr>uid</xsp:expr></esql:parameter></esql:query>
  +             <esql:results>
  +               <esql:row-results>
  +                 <xsp:logic>
  +                   uid=<esql:get-int column="uid"/>;
  +                   uname=<esql:get-string column="uname"/>;
  +                   name=<esql:get-string column="name"/>;
  +                firstname=<esql:get-string column="firstname"/>;
  +                 </xsp:logic>
  +               </esql:row-results>
  +             </esql:results>
  +           </esql:execute-query>
  +         }  
  +      </xsp:logic>
  +
  +
  +      <h1>Edit User's Groups</h1>
  +      <table cellpadding="2" cellspacing="2" border="0">
  +        <tbody>
  +          <form>
               <tr>
  -              <td>
  -              <table border="0">
  +              <td valign="Top" align="Right">uname
  +            </td>
  +            <td valign="Top">
  +              <input type="text" name="user.uname">
  +                <xsp:attribute 
name="value"><xsp:expr>uname</xsp:expr></xsp:attribute>
  +              </input>
  +            </td>
  +            <td>
  +            </td>
  +          </tr>
  +          <tr>
  +            <td valign="Top" align="Right">firstname, name</td>
  +            <td>
  +              <input type="text" name="user.firstname">
  +                <xsp:attribute 
name="value"><xsp:expr>firstname</xsp:expr></xsp:attribute>
  +              </input>,
  +              <input type="text" name="user.name">
  +                <xsp:attribute 
name="value"><xsp:expr>name</xsp:expr></xsp:attribute>
  +              </input>
  +            </td>
  +            <td>
  +              <input type="hidden" name="user.uid">
  +                <xsp:attribute 
name="value"><xsp:expr>uid</xsp:expr></xsp:attribute>
  +              </input>
  +              <input type="submit" name="upd-user" value="update"/>
  +            </td>
  +          </tr>
  +        </form>
  +        <tr>
  +          <td valign="Top">
  +          </td>
  +          <td valign="Top" align="right">
  +            <form>
  +              <table border="1">
                   <tbody>
                     <tr>
  -                    <td>current groups</td>
  -                  </tr>
  -                  <tr>
                       <td>
  -                 <select multiple="1" name="user_groups.gid" size="7">
  -                     <esql:execute-query>
  -                        <esql:query>select gid, gname from user_groups, 
groups where user_groups.gid = groups.gid and uid=<esql:parameter 
type="int"><xsp:expr>uid</xsp:expr></esql:parameter> order by gname</esql:query>
  -                        <esql:results>
  -                             <esql:row-results>
  -                                <option>                             
  -                                   <xsp:attribute 
name="value"><esql:get-string column="gid"/></xsp:attribute>
  -                                   <esql:get-string column="gname"/>
  -                                </option>
  -                             </esql:row-results>
  -                        </esql:results>
  -                     </esql:execute-query>
  -                 </select>
  +                      <table border="0">
  +                        <tbody>
  +                          <tr>
  +                            <td>current groups</td>
  +                          </tr>
  +                          <tr>
  +                            <td>
  +                              <select multiple="1" name="user_groups.gid" 
size="7">
  +                                <esql:execute-query>
  +                                  <esql:query>select gid, gname from 
user_groups, groups where user_groups.gid = groups.gid and uid=<esql:parameter 
type="int"><xsp:expr>uid</xsp:expr></esql:parameter> order by gname</esql:query>
  +                                  <esql:results>
  +                                    <esql:row-results>
  +                                      <option>                               
  +                                        <xsp:attribute 
name="value"><esql:get-string column="gid"/></xsp:attribute>
  +                                        <esql:get-string column="gname"/>
  +                                      </option>
  +                                    </esql:row-results>
  +                                  </esql:results>
  +                                </esql:execute-query>
  +                              </select>
  +                            </td>
  +                          </tr>
  +                          <tr>
  +                            <td valign="Top">
  +                              <input type="hidden" name="user_groups.uid">
  +                                <xsp:attribute 
name="value"><xsp:expr>uid</xsp:expr></xsp:attribute>
  +                              </input>
  +                              <input type="submit" name="remove-groups" 
value="remove"/>
  +                            </td>
  +                          </tr>
  +                        </tbody>
  +                      </table>
                       </td>
                     </tr>
  -                  <tr>
  -                    <td valign="Top">
  -                    <input type="hidden" name="user_groups.uid">
  -                       <xsp:attribute 
name="value"><xsp:expr>uid</xsp:expr></xsp:attribute>
  -                    </input>
  -                    <input type="submit" name="remove-groups" 
value="remove"/></td>
  -                  </tr>
                   </tbody>
                 </table>
  -              </td>
  -            </tr>
  -          </tbody>
  -        </table>
  -      </form>
  -      </td>
  -      <td valign="Top" align="left">
  -      <form>
  -        <table border="1">
  -          <tbody>
  -            <tr>
  -              <td>
  -              <table border="0">
  +            </form>
  +          </td>
  +          <td valign="Top" align="left">
  +            <form>
  +              <table border="1">
                   <tbody>
                     <tr>
  -                    <td>available groups</td>
  -                  </tr>
  -                  <tr>
                       <td>
  -                    <select name="user_groups.gid" multiple="1" size="7">
  -                     <esql:execute-query>
  -                        <esql:query>select gid, gname from groups where gid 
not in (select gid from user_groups where uid=<esql:parameter 
type="int"><xsp:expr>uid</xsp:expr></esql:parameter>) order by 
gname</esql:query>
  -                        <esql:results>
  -                             <esql:row-results>
  -                                <option>                             
  -                                   <xsp:attribute 
name="value"><esql:get-string column="gid"/></xsp:attribute>
  -                                   <esql:get-string column="gname"/>
  -                                </option>
  -                             </esql:row-results>
  -                        </esql:results>
  -                     </esql:execute-query>
  -                    </select>
  -                    </td>
  -                  </tr>
  -                  <tr>
  -                    <td valign="Top">
  -                    <input type="hidden" name="user_groups.uid">
  -                       <xsp:attribute 
name="value"><xsp:expr>uid</xsp:expr></xsp:attribute>
  -                    </input>
  -                    <input type="submit" name="add-groups" value="add"/></td>
  -                  </tr>
  -                </tbody>
  -              </table>
  -              </td>
  -            </tr>
  -          </tbody>
  -        </table>
  -      </form>
  -      </td>
  -    </tr>
  -  </tbody>
  -</table>
  -  <div align="Right"><form action="user-list"><input value="back to list" 
type="submit"/></form></div>
  -
  -  </esql:connection>
  -
  -  <hr/>
  -
  -  <p><h3>Request Attributes</h3></p>
  -  <p>
  -  <table border="0">
  -  <tbody>
  -  <xsp:logic>{
  -       Enumeration e=request.getAttributeNames();
  -       while ( e.hasMoreElements() ) {
  -           String attribute = (String) e.nextElement();
  -           Object value = request.getAttribute(attribute);
  -           <tr>
  -           <td align="right"><xsp:expr>attribute</xsp:expr></td>
  -           <td>="<xsp:expr>value</xsp:expr>"</td>
  -           </tr>
  -       }
  -  }</xsp:logic>
  -  </tbody>
  -  </table><br/>
  -  </p>
  -  <hr/>
  -
  -  <p><h3>Request Parameters</h3></p>
  -  <p>
  -  <table border="0">
  -  <tbody>
  -  <xsp:logic>{
  -       Enumeration e=request.getParameterNames();
  -       while ( e.hasMoreElements() ) {
  -           String attribute = (String) e.nextElement();
  -           Object[] value = request.getParameterValues(attribute);
  -        for (int i=0; i &lt; value.length; i++) {
  -              <tr>
  -              <td 
align="right"><xsp:expr>attribute</xsp:expr>[<xsp:expr>i</xsp:expr>]</td>
  -              <td>="<xsp:expr>value[i]</xsp:expr>"</td>
  -              </tr>
  -        }
  -       }
  -  }</xsp:logic>
  -  </tbody>
  -  </table><br/>
  -  </p>
  -  <hr/>
  -
  +                      <table border="0">
  +                        <tbody>
  +                          <tr>
  +                            <td>available groups</td>
  +                          </tr>
  +                          <tr>
  +                            <td>
  +                              <select name="user_groups.gid" multiple="1" 
size="7">
  +                                <esql:execute-query>
  +                                  <esql:query>select gid, gname from groups 
where gid not in (select gid from user_groups where uid=<esql:parameter 
type="int"><xsp:expr>uid</xsp:expr></esql:parameter>) order by 
gname</esql:query>
  +                                  <esql:results>
  +                                    <esql:row-results>
  +                                      <option>                               
  +                                        <xsp:attribute 
name="value"><esql:get-string column="gid"/></xsp:attribute>
  +                                        <esql:get-string column="gname"/>
  +                                      </option>
  +                                    </esql:row-results>
  +                                  </esql:results>
  +                                </esql:execute-query>
  +                              </select>
  +                            </td>
  +                          </tr>
  +                          <tr>
  +                            <td valign="Top">
  +                              <input type="hidden" name="user_groups.uid">
  +                                <xsp:attribute 
name="value"><xsp:expr>uid</xsp:expr></xsp:attribute>
  +                              </input>
  +                              <input type="submit" name="add-groups" 
value="add"/></td>
  +                            </tr>
  +                          </tbody>
  +                        </table>
  +                      </td>
  +                    </tr>
  +                  </tbody>
  +                </table>
  +              </form>
  +            </td>
  +          </tr>
  +        </tbody>
  +      </table>
  +      <div align="Right"><form action="user-list"><input value="back to 
list" type="submit"/></form></div>
  +
  +    </esql:connection>
  +
  +    <hr/>
  +
  +    <p><h3>Request Attributes</h3></p>
  +    <p>
  +      <table border="0">
  +        <tbody>
  +          <xsp:logic>{
  +             Enumeration e=request.getAttributeNames();
  +             while ( e.hasMoreElements() ) {
  +                 String attribute = (String) e.nextElement();
  +                 Object value = request.getAttribute(attribute);
  +                 <tr>
  +                   <td align="right"><xsp:expr>attribute</xsp:expr></td>
  +                   <td>="<xsp:expr>value</xsp:expr>"</td>
  +                 </tr>
  +             }
  +          }</xsp:logic>
  +        </tbody>
  +      </table>
  +    </p>
  +
  +    <hr/>
  +
  +    <p><h3>Request Parameters</h3></p>
  +    <p>
  +      <table border="0">
  +        <tbody>
  +          <xsp:logic>{
  +               Enumeration e=request.getParameterNames();
  +               while ( e.hasMoreElements() ) {
  +                   String attribute = (String) e.nextElement();
  +                   Object[] value = request.getParameterValues(attribute);
  +                   for (int i=0; i &lt; value.length; i++) {
  +                      <tr>
  +                        <td 
align="right"><xsp:expr>attribute</xsp:expr>[<xsp:expr>i</xsp:expr>]</td>
  +                        <td>="<xsp:expr>value[i]</xsp:expr>"</td>
  +                      </tr>
  +                   }
  +               }
  +          }</xsp:logic>
  +        </tbody>
  +      </table>
  +    </p>
   
  +    <hr/>
   
  -
     </page>
  +
   </xsp:page>
  
  
  
  1.2       +1 -1      xml-cocoon2/scratchpad/webapp/mount/mod-db/schema.sql
  
  Index: schema.sql
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/scratchpad/webapp/mount/mod-db/schema.sql,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- schema.sql        2001/11/19 16:28:32     1.1
  +++ schema.sql        2001/11/23 10:50:35     1.2
  @@ -8,7 +8,7 @@
   create table user (
        uid integer identity primary key,
        name varchar(50),
  -     surname varchar(50),
  +     firstname varchar(50),
        uname varchar(20),
        unique (uname)
   );
  
  
  
  1.2       +52 -17    xml-cocoon2/scratchpad/webapp/mount/mod-db/sitemap.xmap
  
  Index: sitemap.xmap
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/scratchpad/webapp/mount/mod-db/sitemap.xmap,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- sitemap.xmap      2001/11/19 16:28:32     1.1
  +++ sitemap.xmap      2001/11/23 10:50:35     1.2
  @@ -5,6 +5,8 @@
     <!-- ========================= Components ============================== 
-->
   
     <map:components>
  +    <!-- most components are inherited from parent sitemap -->
  +    <!-- just make sure that defaults suit our needs -->
   
       <map:generators default="file"/>
   
  @@ -14,17 +16,19 @@
   
       <map:serializers default="html"/>
   
  -    <map:selectors default="browser">
  -      <map:selector name="request" 
src="org.apache.cocoon.selection.RequestSelectorFactory"/>
  -    </map:selectors>
  -
  -    <map:matchers default="wildcard">
  -      <map:matcher name="wildcard" 
src="org.apache.cocoon.matching.WildcardURIMatcherFactory"/>
  -    </map:matchers>
  +    <map:selectors default="browser"/>
   
  +    <map:matchers default="wildcard"/>
  +
       <map:actions>
  +       <!-- these action are in addition to the ones inherited -->
          <map:action name="mod-db-add" 
src="org.apache.cocoon.acting.ModularDatabaseAddAction">
         <descriptor>context://mount/mod-db/database.xml</descriptor>
  +      <throw-exception>false</throw-exception>
  +      <!-- shall we throw an exception in addition to rolling back
  +           the transaction when encountering an error during
  +           database ops? 
  +      -->
         <!-- <mode name="auto" 
src="org.apache.cocoon.acting.ModularDatabaseAccess.IfxSerialKeyAttributeHelper"/>
 -->
         <mode name="auto" 
src="org.apache.cocoon.acting.ModularDatabaseAccess.HsqlIdentityKeyAttributeHelper"/>
         <mode name="request" 
src="org.apache.cocoon.acting.ModularDatabaseAccess.RequestParameterHelper"/>
  @@ -33,6 +37,14 @@
          </map:action>
          <map:action name="mod-db-del" 
src="org.apache.cocoon.acting.ModularDatabaseDeleteAction">
         <descriptor>context://mount/mod-db/database.xml</descriptor>
  +      <throw-exception>false</throw-exception>
  +      <!--
  +         It doesn't make sense to declare AutoIncrementHelpers for
  +         this action, but until component handling is removed from
  +         ModularDatabaseAction and done e.g. in sitemap,
  +         ModularDatabaseAction will complain if such a helper is
  +         missing. 
  +      -->
         <!-- <mode name="auto" 
src="org.apache.cocoon.acting.ModularDatabaseAccess.IfxSerialKeyAttributeHelper"/>
 -->
         <mode name="auto" 
src="org.apache.cocoon.acting.ModularDatabaseAccess.HsqlIdentityKeyAttributeHelper"/>
         <mode name="request" 
src="org.apache.cocoon.acting.ModularDatabaseAccess.RequestParameterHelper"/>
  @@ -41,6 +53,14 @@
          </map:action>
          <map:action name="mod-db-upd" 
src="org.apache.cocoon.acting.ModularDatabaseUpdateAction">
         <descriptor>context://mount/mod-db/database.xml</descriptor>
  +      <throw-exception>false</throw-exception>
  +      <!--
  +         It doesn't make sense to declare AutoIncrementHelpers for
  +         this action, but until component handling is removed from
  +         ModularDatabaseAction and done e.g. in sitemap,
  +         ModularDatabaseAction will complain if such a helper is
  +         missing. 
  +      -->
         <!-- <mode name="auto" 
src="org.apache.cocoon.acting.ModularDatabaseAccess.IfxSerialKeyAttributeHelper"/>
 -->
         <mode name="auto" 
src="org.apache.cocoon.acting.ModularDatabaseAccess.HsqlIdentityKeyAttributeHelper"/>
         <mode name="request" 
src="org.apache.cocoon.acting.ModularDatabaseAccess.RequestParameterHelper"/>
  @@ -68,8 +88,22 @@
   
      <!-- ========================== Modular DB 
================================= -->
   
  +       <map:match pattern="">
  +          <map:redirect-to uri="user-list"/>
  +       </map:match>
  +
  +
          <map:match pattern="*">
   
  +          <!--
  +          First, the logic to do all the database operations. Note,
  +          that we do no parameter validation here, just see if some
  +          parameters are present. For a real application, you'd
  +          want to check their values as well. Note too, that in a
  +          more complex setup you'd want to use an action set for
  +          this rather than spell it out everywhere.
  +       -->
  +
             <!-- ______________________________ inserts 
______________________________ -->
   
             <!-- add new groups to a user's groups -->
  @@ -80,25 +114,28 @@
             </map:act>
          </map:act>
   
  -          <!-- add one new user -->
  +          <!-- add onw new group -->
          <map:act type="req-params">
  -          <map:parameter name="parameters" value="add-user user.name 
user.surname user.uname"/>
  +          <map:parameter name="parameters" value="add-group groups.gname"/>
             <map:act type="mod-db-add">
  -             <map:parameter name="table-set" value="user"/>
  +             <map:parameter name="table-set" value="groups"/>
             </map:act>
          </map:act>
        
  -          <!-- add onw new group -->
  +          <!-- add one new user -->
  +       <!-- Actually, this one is not used anymore. The one below
  +            works well when no groups are supplied.
  +        -->
          <map:act type="req-params">
  -          <map:parameter name="parameters" value="add-group groups.gname"/>
  +          <map:parameter name="parameters" value="add-user user.name 
user.firstname user.uname"/>
             <map:act type="mod-db-add">
  -             <map:parameter name="table-set" value="groups"/>
  +             <map:parameter name="table-set" value="user"/>
             </map:act>
          </map:act>
        
             <!-- add one new user plus groups -->
          <map:act type="req-params">
  -          <map:parameter name="parameters" value="add-user-groups user.name 
user.surname user.uname"/>
  +          <map:parameter name="parameters" value="add-user-groups user.name 
user.firstname user.uname"/>
             <map:act type="mod-db-add">
                <map:parameter name="table-set" value="user+groups"/>
             </map:act>
  @@ -108,7 +145,7 @@
   
             <!-- update one user -->
          <map:act type="req-params">
  -          <map:parameter name="parameters" value="upd-user user.uid 
user.name user.surname user.uname"/>
  +          <map:parameter name="parameters" value="upd-user user.uid 
user.name user.firstname user.uname"/>
             <map:act type="mod-db-upd">
                <map:parameter name="table-set" value="user"/>
             </map:act>
  @@ -152,8 +189,6 @@
             <!-- ______________________________ content  
______________________________ -->
   
          <map:generate type="serverpages" src="{1}.xsp"/>
  -       <map:label name="content"/>
  -
          <map:transform src="context://stylesheets/dynamic-page2html.xsl">
             <map:parameter name="view-source" value="{1}.xsp"/>
          </map:transform>
  
  
  
  1.2       +241 -346  xml-cocoon2/scratchpad/webapp/mount/mod-db/user-list.xsp
  
  Index: user-list.xsp
  ===================================================================
  RCS file: /home/cvs/xml-cocoon2/scratchpad/webapp/mount/mod-db/user-list.xsp,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- user-list.xsp     2001/11/19 16:28:32     1.1
  +++ user-list.xsp     2001/11/23 10:50:35     1.2
  @@ -5,354 +5,249 @@
             xmlns:xsp="http://apache.org/xsp";
          xmlns:esql="http://apache.org/cocoon/SQL/v2";
             xmlns:xsp-request="http://apache.org/xsp/request/2.0";
  ->
  -<!--
  --->
  -<xsp:structure>
  -   <xsp:include>java.util.Enumeration</xsp:include>
  -</xsp:structure>
  -
  -  <page>
  - 
  -   <title>user-list</title>
  -
  -   <content>
  -
  -
  -  <h1>Modular Database Actions</h1> 
  -
  -  <hr/> 
  -
  -  <p>The intention is to factor out those parts that are dependent on
  -  the utilised DBMS as well as the methods used to obtain the values
  -  and communicate results. Therefore three classes of adaptors
  -  exist:</p>
  -
  -  <ol>
  -    <li>Attribute Helpers read data from some source (e.g. the request
  -     object or session attributes or whatever)</li> 
  -
  -    <li>Key Attribute Helpers determine the value of a key attribute
  -        column in a database. This could be by querying the database,
  -        reading from an arbitrary source (e.g. request object) or just
  -        skipping the column when inserting a row and querying the
  -        database afterwards. This needs to be done e.g. for Informix's
  -        SERIAL or HSQLDB's IDENTITY column types.</li>
  -
  -   <li>Output Helpers send the data to an arbitrary
  -       destination. Again, this could be request attributes or
  -       anything else. When the database transaction finishes, it is
  -       signalled to them whether the transaction succeeded or
  -       failed.</li>
  -  </ol>
  -  <hr/>
  -  <!-- 
  -                                   forms 
  -  -->
  -
  +  >
     <!--
  -
  -  <h2>Insert a user</h2>
  -  <blockquote>
  -    <form method="Get">
  -      <table cellpadding="2" cellspacing="2" border="0">
  -     <tbody>
  -       <tr>
  -         <td valign="Top" align="Right">surname</td>
  -         <td valign="Top">
  -           <input type="text" name="user.surname" size="20" maxsize="20">
  -             <xsp:attribute name="value"><xsp-request:get-parameter 
default="" name="user.surname"/></xsp:attribute>
  -           </input>
  -         </td>
  -       </tr>
  -       <tr>
  -         <td valign="Top" align="Right">name
  -         </td>
  -         <td valign="Top"><input type="text" name="user.name" size="20" 
maxsize="20"><xsp:attribute name="value"><xsp-request:get-parameter default="" 
name="user.name"/></xsp:attribute></input></td>
  -       </tr>
  -       <tr>
  -         <td valign="Top" align="Right">uname
  -         </td>
  -         <td valign="Top"><input type="text" name="user.uname" size="20" 
maxsize="20"><xsp:attribute name="value"><xsp-request:get-parameter default="" 
name="user.uname"/></xsp:attribute></input>
  -         </td>
  -       </tr>
  -       <tr>
  -         <td valign="Top">
  -         </td>
  -         <td align="Right"><input type="submit" name="add-user" 
value="OK"/></td>
  -       </tr>
  -     </tbody>
  -      </table>
  -    </form>
  -    </blockquote>
  -    <hr/>
  -
  -
  -    <h2>Add groups to a user account</h2>
  -    <blockquote>
  -      <form method="Get">
  -     <table cellpadding="2" cellspacing="2" border="0">
  -       <tbody>
  -         <tr>
  -           <td valign="Top" align="Right">user</td>
  -           <td valign="Top">
  -              <select name="user_groups.uid" size="1">
  -                 <esql:connection>
  -                    <esql:pool>personnel</esql:pool>
  -                    <esql:execute-query>
  -                       <esql:query>select uid, uname from user order by 
name, surname</esql:query>
  -                       <esql:results>
  -                          <esql:row-results>
  -                             <option>                                
  -                                <xsp:attribute name="value"><esql:get-string 
column="uid"/></xsp:attribute>
  -                                <esql:get-string column="uname"/>
  -                             </option>
  -                          </esql:row-results>
  -                       </esql:results>
  -                    </esql:execute-query>
  -                 </esql:connection>
  -              </select>
  -           </td>
  -           <td>
  -           </td>
  -         </tr>
  -         <tr>
  -           <td valign="Top" align="Right">groups</td>
  -           <td valign="Top">
  -              <select multiple="1" name="user_groups.gid" size="4">
  -                 <esql:connection>
  -                    <esql:pool>personnel</esql:pool>
  -                    <esql:execute-query>
  -                       <esql:query>select gid, gname from groups order by 
gname</esql:query>
  -                       <esql:results>
  -                          <esql:row-results>
  -                             <option>                                
  -                                <xsp:attribute name="value"><esql:get-string 
column="gid"/></xsp:attribute>
  -                                <esql:get-string column="gname"/>
  -                             </option>
  -                          </esql:row-results>
  -                       </esql:results>
  -                    </esql:execute-query>
  -                 </esql:connection>
  -              </select>
  -           </td>
  -         </tr>
  -         <tr>
  -           <td valign="Top">
  -           </td>
  -           <td>
  -           </td>
  -           <td align="Right"><input type="submit" name="add-groups" 
value="OK"/></td>
  -         </tr>
  -       </tbody>
  -     </table>
  -      </form>
  -      </blockquote>
  -      -->
  -        <!--
  -                                            current db content
  -        -->
  -
  -     <h2>Current database content</h2>
  -
  -             <esql:connection>           
  -                <esql:pool>personnel</esql:pool>
  -               
  -        <p>
  -        <sqltbl>
  -                   <esql:execute-query>
  -                      <esql:query>select * from user order by name, surname, 
uname, uid</esql:query>
  -                      <esql:results>
  -                         <esql:row-results>
  -                    
  -                              <sqltblrow>
  -                         <name>
  -                            <esql:get-string column="name"/>
  -                         </name>
  -                         <surname>
  -                            <esql:get-string column="surname"/>
  -                         </surname>
  -                         <uname>
  -                            <esql:get-string column="uname"/>
  -                         </uname>
  -                         <action>
  -                            <form action="edit-groups">
  -                               <input type="hidden" name="user.uid">
  -                                  <xsp:attribute 
name="value"><esql:get-string column="uid"/></xsp:attribute>
  -                               </input>
  -                            <input type="submit" name="edit-user" 
value="edit"/>
  -                            </form>
  -                            <form>
  -                               <input type="hidden" name="user.uid">
  -                                  <xsp:attribute 
name="value"><esql:get-string column="uid"/></xsp:attribute>
  -                               </input>
  -                               <input type="submit" name="del-user" 
value="delete"/>
  -                            </form>
  -                         </action>
  -                              </sqltblrow>
  -                    
  -                         </esql:row-results>
  -                      </esql:results>
  -                      <esql:error-results>
  -                         <error><esql:get-message/></error>
  -                      </esql:error-results>
  -                   </esql:execute-query>
  -           <form method="Get">
  -              <sqltblrow>
  -                 <name>
  -                    <input type="text" name="user.name" size="20" 
maxsize="20">
  -                       <xsp:attribute name="value"><!-- 
<xsp-request:get-parameter default="" name="user.name"/> --></xsp:attribute>
  -                    </input>
  -                 </name>
  -                 <surname>
  -                    <input type="text" name="user.surname" size="20" 
maxsize="20">
  -                       <xsp:attribute name="value"><!-- 
<xsp-request:get-parameter default="" name="user.surname"/> --></xsp:attribute>
  -                    </input>
  -                 </surname>
  -                 <uname>
  -                    <input type="text" name="user.uname" size="20" 
maxsize="20">
  -                       <xsp:attribute name="value"><!-- 
<xsp-request:get-parameter default="" name="user.uname"/> --></xsp:attribute>
  -                    </input>
  -                 </uname>
  -                 <action>
  -                    <select multiple="1" name="user_groups.gid" size="4">
  -                       <esql:execute-query>
  -                          <esql:query>select gid, gname from groups order by 
gname</esql:query>
  -                          <esql:results>
  -                             <esql:row-results>
  -                                <option>                             
  -                                   <xsp:attribute 
name="value"><esql:get-string column="gid"/></xsp:attribute>
  -                                   <esql:get-string column="gname"/>
  -                                </option>
  -                             </esql:row-results>
  -                          </esql:results>
  -                       </esql:execute-query>
  -                    </select>
  -                    <input type="submit" name="add-user-groups" value="new 
user"/>
  +       -->
  +  <xsp:structure>
  +    <xsp:include>java.util.Enumeration</xsp:include>
  +  </xsp:structure>
  +    
  +  <page>
  +    
  +    <title>user-list</title>
  +    
  +    <content>
  +        
  +
  +      <h1>Modular Database Actions</h1> 
  +
  +      <hr/> 
  +
  +      <p>The intention is to factor out those parts that are dependent on
  +      the utilised DBMS as well as the methods used to obtain the values
  +      and communicate results. Therefore three classes of adaptors
  +      exist:</p>
  +
  +      <ol>
  +        <li>Attribute Helpers read data from some source (e.g. the request
  +            object or session attributes or whatever)</li> 
  +
  +        <li>Auto Increment Helpers determine the value of a key attribute
  +            column in a database if it's is of auto increment type. This
  +            could be by querying the database, reading from an arbitrary
  +            source (e.g. request object) or just skipping the column when
  +            inserting a row and querying the database afterwards. This
  +            needs to be done e.g. for Informix's SERIAL or HSQLDB's
  +            IDENTITY column types.</li>
  +
  +       <li>Output Helpers send the data to an arbitrary
  +           destination. Again, this could be request attributes or
  +           anything else. When the database transaction finishes, it is
  +           signalled to them whether the transaction succeeded or
  +           failed.</li>
  +      </ol>
  +      <hr/>
  +
  +      <h2>Current database content</h2>
  +
  +      <esql:connection>          
  +        <esql:pool>personnel</esql:pool>
  +               
  +        <p>
  +          <sqltbl>
  +            <esql:execute-query>
  +              <esql:query>select * from user order by name, firstname, 
uname, uid</esql:query>
  +              <esql:results>
  +                <esql:row-results>
  +                            
  +                  <sqltblrow>
  +                    <name>
  +                      <esql:get-string column="name"/>
  +                    </name>
  +                    <firstname>
  +                      <esql:get-string column="firstname"/>
  +                    </firstname>
  +                    <uname>
  +                      <esql:get-string column="uname"/>
  +                    </uname>
  +                    <action>
  +                      <form action="edit-groups">
  +                        <input type="hidden" name="user.uid">
  +                          <xsp:attribute name="value"><esql:get-string 
column="uid"/></xsp:attribute>
  +                        </input>
  +                        <input type="submit" name="edit-user" value="edit"/>
  +                      </form>
  +                      <form>
  +                        <input type="hidden" name="user.uid">
  +                          <xsp:attribute name="value"><esql:get-string 
column="uid"/></xsp:attribute>
  +                        </input>
  +                        <input type="submit" name="del-user" value="delete"/>
  +                      </form>
                       </action>
  -              </sqltblrow>   
  -           </form>
  -           </sqltbl>
  -     </p>
  -
  -        <p>
  -        <sqltbl>
  -                   <esql:execute-query>
  -                      <esql:query>select * from groups order by 
gname</esql:query>
  -              <esql:results>
  -                 <esql:row-results>
  -                    <form>
  -                          <sqltblrow>
  -                             <gname>
  -                                <input type="text" name="groups.gname">
  -                                   <xsp:attribute 
name="value"><esql:get-string column="gname"/></xsp:attribute>
  -                                </input>
  -                                <input type="hidden" name="groups.gid">
  -                                   <xsp:attribute 
name="value"><esql:get-string column="gid"/></xsp:attribute>
  -                                </input>
  -                                <input type="submit" name="upd-group" 
value="update"/>
  -                                <input type="submit" name="del-group" 
value="delete"/>
  -                            </gname>
  -                              </sqltblrow>
  -                    </form>
  -                         </esql:row-results>
  -                      </esql:results>
  -                      <esql:error-results>
  -                         <error><esql:get-message/></error>
  -                      </esql:error-results>
  -                   </esql:execute-query>
  -           <sqltblrow>
  -              <gname>
  -                 <form>
  -                    <input type="text" name="groups.gname" size="20" 
maxsize="20">
  -                       <xsp:attribute name="value"><!-- 
<xsp-request:get-parameter default="" name="groups.gname"/> --></xsp:attribute>
  -                    </input>
  -                    <input type="submit" name="add-group" value="new group"/>
  -                 </form>
  -              </gname>
  -           </sqltblrow>
  -           </sqltbl>
  -        </p>
  -
  -        <p>
  -        <form>
  -                <esql:execute-query>
  -                   <esql:query>select user.uid, user.uname, groups.gid, 
groups.gname from user, user_groups, groups where user.uid=user_groups.uid and 
user_groups.gid=groups.gid order by user.uname, groups.gname</esql:query>
  -                   <esql:results>
  -              <sqltbl>
  -                      <esql:row-results>
  -                 <form action="edit-groups">
  -                            <sqltblrow>
  -                          <uname>
  -                          <input type="hidden" name="user.uid">
  -                             <xsp:attribute name="value"><esql:get-string 
column="uid"/></xsp:attribute>
  -                          </input>
  -                          <esql:get-string column="uname"/>
  -                       </uname>
  -                          <gname><esql:get-string column="gname"/></gname>
  -                       <action>
  -                          <input value="edit groups" type="submit"/>
  -                       </action>
  -                            </sqltblrow>
  -                 </form>
  -                      </esql:row-results>
  -              </sqltbl>
  -                   </esql:results>
  -                   <esql:error-results>
  -                      <error><esql:get-message/></error>
  -                   </esql:error-results>
  -                </esql:execute-query>
  -        </form>
  -        </p>
  -             </esql:connection>
  -   
  -  <hr/>
  -
  -  <p><h3>Request Attributes</h3></p>
  -  <p>
  -  <table border="0">
  -  <tbody>
  -  <xsp:logic>{
  -       Enumeration e=request.getAttributeNames();
  -       while ( e.hasMoreElements() ) {
  -           String attribute = (String) e.nextElement();
  -           Object value = request.getAttribute(attribute);
  -           <tr>
  -           <td align="right"><xsp:expr>attribute</xsp:expr></td>
  -           <td>="<xsp:expr>value</xsp:expr>"</td>
  -           </tr>
  -       }
  -  }</xsp:logic>
  -  </tbody>
  -  </table><br/>
  -  </p>
  -  <hr/>
  -
  -  <p><h3>Request Parameters</h3></p>
  -  <p>
  -  <table border="0">
  -  <tbody>
  -  <xsp:logic>{
  -       Enumeration e=request.getParameterNames();
  -       while ( e.hasMoreElements() ) {
  -           String attribute = (String) e.nextElement();
  -           Object[] value = request.getParameterValues(attribute);
  -        for (int i=0; i &lt; value.length; i++) {
  -              <tr>
  -              <td 
align="right"><xsp:expr>attribute</xsp:expr>[<xsp:expr>i</xsp:expr>]</td>
  -              <td>="<xsp:expr>value[i]</xsp:expr>"</td>
  -              </tr>
  -        }
  -       }
  -  }</xsp:logic>
  -  </tbody>
  -  </table><br/>
  -  </p>
  -
  -   <hr/>
  -
  -
  -   </content>
  +                  </sqltblrow>
  +                            
  +                </esql:row-results>
  +              </esql:results>
  +              <esql:error-results>
  +                <error><esql:get-message/></error>
  +              </esql:error-results>
  +            </esql:execute-query>
  +            <form method="Get">
  +              <sqltblrow>
  +                <name>
  +                  <input type="text" name="user.name" size="20" maxsize="20">
  +                    <xsp:attribute name="value"><!-- 
<xsp-request:get-parameter default="" name="user.name"/> --></xsp:attribute>
  +                  </input>
  +                </name>
  +                <firstname>
  +                  <input type="text" name="user.firstname" size="20" 
maxsize="20">
  +                    <xsp:attribute name="value"><!-- 
<xsp-request:get-parameter default="" name="user.firstname"/> 
--></xsp:attribute>
  +                  </input>
  +                </firstname>
  +                <uname>
  +                  <input type="text" name="user.uname" size="20" 
maxsize="20">
  +                    <xsp:attribute name="value"><!-- 
<xsp-request:get-parameter default="" name="user.uname"/> --></xsp:attribute>
  +                  </input>
  +                </uname>
  +                <action>
  +                  <select multiple="1" name="user_groups.gid" size="4">
  +                    <esql:execute-query>
  +                      <esql:query>select gid, gname from groups order by 
gname</esql:query>
  +                      <esql:results>
  +                        <esql:row-results>
  +                          <option>                           
  +                            <xsp:attribute name="value"><esql:get-string 
column="gid"/></xsp:attribute>
  +                            <esql:get-string column="gname"/>
  +                          </option>
  +                        </esql:row-results>
  +                      </esql:results>
  +                    </esql:execute-query>
  +                  </select>
  +                  <input type="submit" name="add-user-groups" value="new 
user"/>
  +                </action>
  +              </sqltblrow>   
  +            </form>
  +          </sqltbl>
  +        </p>
  +
  +        <p>
  +          <sqltbl>
  +            <esql:execute-query>
  +              <esql:query>select * from groups order by gname</esql:query>
  +              <esql:results>
  +                <esql:row-results>
  +                  <form>
  +                    <sqltblrow>
  +                      <gname>
  +                        <input type="text" name="groups.gname">
  +                          <xsp:attribute name="value"><esql:get-string 
column="gname"/></xsp:attribute>
  +                        </input>
  +                        <input type="hidden" name="groups.gid">
  +                          <xsp:attribute name="value"><esql:get-string 
column="gid"/></xsp:attribute>
  +                        </input>
  +                        <input type="submit" name="upd-group" 
value="update"/>
  +                        <input type="submit" name="del-group" 
value="delete"/>
  +                      </gname>
  +                    </sqltblrow>
  +                  </form>
  +                </esql:row-results>
  +              </esql:results>
  +              <esql:error-results>
  +                <error><esql:get-message/></error>
  +              </esql:error-results>
  +            </esql:execute-query>
  +            <sqltblrow>
  +              <gname>
  +                <form>
  +                  <input type="text" name="groups.gname" size="20" 
maxsize="20">
  +                    <xsp:attribute name="value"><!-- 
<xsp-request:get-parameter default="" name="groups.gname"/> --></xsp:attribute>
  +                  </input>
  +                  <input type="submit" name="add-group" value="new group"/>
  +                </form>
  +              </gname>
  +            </sqltblrow>
  +          </sqltbl>
  +        </p>
  +
  +        <p>
  +          <form>
  +            <esql:execute-query>
  +              <esql:query>select user.uid, user.uname, groups.gid, 
groups.gname from user, user_groups, groups where user.uid=user_groups.uid and 
user_groups.gid=groups.gid order by user.uname, groups.gname</esql:query>
  +              <esql:results>
  +                <sqltbl>
  +                  <esql:row-results>
  +                    <form action="edit-groups">
  +                      <sqltblrow>
  +                        <uname>
  +                          <input type="hidden" name="user.uid">
  +                            <xsp:attribute name="value"><esql:get-string 
column="uid"/></xsp:attribute>
  +                          </input>
  +                          <esql:get-string column="uname"/>
  +                        </uname>
  +                        <gname><esql:get-string column="gname"/></gname>
  +                        <action>
  +                          <input value="edit groups" type="submit"/>
  +                        </action>
  +                      </sqltblrow>
  +                    </form>
  +                  </esql:row-results>
  +                </sqltbl>
  +              </esql:results>
  +              <esql:error-results>
  +                <error><esql:get-message/></error>
  +              </esql:error-results>
  +            </esql:execute-query>
  +          </form>
  +        </p>
  +      </esql:connection>
  +       
  +      <hr/>
  +
  +      <p><h3>Request Attributes</h3></p>
  +      <p>
  +        <table border="0">
  +          <tbody>
  +            <xsp:logic>{
  +               Enumeration e=request.getAttributeNames();
  +               while ( e.hasMoreElements() ) {
  +                  String attribute = (String) e.nextElement();
  +                  Object value = request.getAttribute(attribute);
  +                  <tr>
  +                    <td align="right"><xsp:expr>attribute</xsp:expr></td>
  +                    <td>="<xsp:expr>value</xsp:expr>"</td>
  +                  </tr>
  +               }
  +            }</xsp:logic>
  +          </tbody>
  +        </table>
  +      </p>
  +
  +      <hr/>
  +
  +      <p><h3>Request Parameters</h3></p>
  +      <p>
  +        <table border="0">
  +          <tbody>
  +            <xsp:logic>{
  +               Enumeration e=request.getParameterNames();
  +               while ( e.hasMoreElements() ) {
  +                  String attribute = (String) e.nextElement();
  +                  Object[] value = request.getParameterValues(attribute);
  +                  for (int i=0; i &lt; value.length; i++) {
  +                     <tr>
  +                       <td 
align="right"><xsp:expr>attribute</xsp:expr>[<xsp:expr>i</xsp:expr>]</td>
  +                       <td>="<xsp:expr>value[i]</xsp:expr>"</td>
  +                     </tr>
  +                  }
  +               }
  +            }</xsp:logic>
  +          </tbody>
  +        </table><br/>
  +      </p>
  +
  +      <hr/>
  +      
  +    </content>
     </page>
   </xsp:page>
   
  
  
  
  1.2       +70 -951   
xml-cocoon2/scratchpad/src/org/apache/cocoon/acting/ModularDatabaseAddAction.java
  
  Index: ModularDatabaseAddAction.java
  ===================================================================
  RCS file: 
/home/cvs/xml-cocoon2/scratchpad/src/org/apache/cocoon/acting/ModularDatabaseAddAction.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ModularDatabaseAddAction.java     2001/11/19 16:28:33     1.1
  +++ ModularDatabaseAddAction.java     2001/11/23 10:50:35     1.2
  @@ -7,64 +7,19 @@
    
*****************************************************************************/
   package org.apache.cocoon.acting;
   
  -import java.io.IOException;
  -import java.io.InputStream;
  -import java.lang.Class;
  -import java.net.URL;
  +import java.util.Map;
   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.cocoon.util.HashMap;
   
  -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.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.thread.ThreadSafe;
  -import org.apache.avalon.excalibur.component.ExcaliburComponentSelector;
  -import org.apache.avalon.excalibur.component.ExcaliburComponentManager;
  -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.components.url.URLFactory;
  +
   import org.apache.cocoon.environment.Request;
  -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.selection.Selector;
   
  -import org.apache.cocoon.acting.ModularDatabaseAccess.AccessHelper;
  -import org.apache.cocoon.acting.ModularDatabaseAccess.KeyAttributeHelper;
  -import org.apache.cocoon.acting.ModularDatabaseAccess.AttributeHelper;
  -import org.apache.cocoon.acting.ModularDatabaseAccess.OutputHelper;
  +import org.apache.cocoon.acting.ModularDatabaseAccess.AutoIncrementHelper;
   
   /**
    * Adds record in a database. The action can update one or more tables,
  @@ -83,772 +38,101 @@
    * components can utilize the helper components.
    *
    * @author <a href="mailto:[EMAIL PROTECTED]">Christian Haul</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2001/11/19 16:28:33 $
  + * @version CVS $Revision: 1.2 $ $Date: 2001/11/23 10:50:35 $
    */
   public class ModularDatabaseAddAction 
  -    extends AbstractDatabaseAction 
  -    implements Disposable, ThreadSafe, Contextualizable
  +    extends ModularDatabaseAction 
   {
  -
  -    // 
========================================================================
  -    // inner helper classes
  -    // 
========================================================================
  -
  -    protected class Column {
  -     boolean isKey = false;
  -     boolean isSet = false;
  -     String mode = null;
  -     Configuration modeConf = null;
  -     Configuration columnConf = null;
  -    }
  -
  -    protected class CacheHelper {
  -     public String queryString = null;
  -     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();
  -            }
  -     }
  -    }
  -
  -
  -    protected class LookUpKey {
  -     public Configuration tableConf = null;
  -     public Map modeTypes = null;
  -     
  -     public LookUpKey( Configuration tableConf, Map modeTypes ) {
  -         this.tableConf = tableConf;
  -         this.modeTypes = modeTypes;
  -     }
  -    }
  -
  -
  -//     /**
  -//      * This inner class stores extracted configuration data for a
  -//      * table column.
  -//      */
  -//     protected class SetHelper {
  -//   public int master = -1;
  -//   public String mode = null;
  -//   public Configuration conf = null;
  -//   public int numbKeys = 0;
  -//   public boolean[] isKey;
  -//   public boolean[] isSet;
  -//   public String[] modes = null;
  -//   public Configuration[] modeConf = null;
  -     
  -//   SetHelper( int cols ) {
  -//       this(0,cols);
  -//   }
  -     
  -//   SetHelper( int keys, int cols ) {
  -//       numbKeys = keys;
  -//       isKey = new boolean[cols];
  -//       isSet = new boolean[cols];
  -//       modes = new String[cols];
  -//       modeConf = new Configuration[cols];
  -//   }
  -//     }
  -
  -    // 
========================================================================
  -    // constants
  -    // 
========================================================================
  -
  -    private static final String LOCATION = 
"org.apache.cocoon.acting.ModularDatabaseAddAction";
  -    private static final int BYTE_ARRAY_SIZE = 1024;
  -
  -    static final Integer MODE_INSERT = new Integer( 0 );
  -    static final Integer MODE_OTHERS = new Integer( 1 );
  -    static final Integer MODE_OUTPUT = new Integer( 2 );
  -
  -    // 
========================================================================
  -    // instance vars
  -    // 
========================================================================
  -
  -    // please ignore component management as I know this is ugly and I
  -    // hope that this duty is taken by the sitemap in short term.
  -    // please ignore ====>
  -    protected RoleManager roleManager;
  -    private Configuration defaultConfig;
  -
  -    protected Context context;
  -
  -    /** The component manager instance */
  -    protected ExcaliburComponentManager manager2;
  -
  -    /** The URLFactory instance */
  -    protected URLFactory urlFactory;
  -
  -    protected ExcaliburComponentSelector  modeMapping = null;
  -    protected ExcaliburComponentSelector  outputMapping = null;
  -
  -    // default modes for other / insert operations
  -    protected HashMap defaultModeNames = new HashMap( 3 );
  -
  -    // <==== please ignore
  -    //
  -
  -    protected final Map cachedQueryData = new HashMap();
  -
  -
  -    //
  -    // please ignore ====>
  -
  -    // 
========================================================================
  -    // setup / class loading
  -    // (basically copied from AbstractSitemap)
  -    // This is ugly. Please ignore. Helpers should be handled at sitemap 
level
  -    // so that other components can share them.
  -    // 
========================================================================
  -
       /**
  -     * Set the role manager
  -     */
  -    public void setRoleManager( 
  -                            RoleManager roles, 
  -                            Configuration config
  -                            ) 
  -    {
  -        this.roleManager = roles;
  -        this.defaultConfig = config;
  -    }
  -
  -    /**
  -     * Set the current <code>ComponentManager</code> instance used by this
  -     * <code>Composable</code>.
  -     */
  -    public void compose( 
  -                     ComponentManager manager
  -                     ) 
  -     throws ComponentException 
  -    {
  -     super.compose( manager );
  -     getLogger().debug("compose");
  -        this.manager2 = new ExcaliburComponentManager(manager);
  -        this.manager2.setLogger(getLogger());
  -        this.manager2.contextualize(this.context);
  -        this.manager2.setRoleManager(this.roleManager);
  -
  -     try {
  -         if (this.defaultConfig != null) {
  -             this.manager2.configure(this.defaultConfig);
  -         }
  -         this.urlFactory = (URLFactory)manager.lookup(URLFactory.ROLE);
  -         this.modeMapping = new ExcaliburComponentSelector();
  -         this.outputMapping = new ExcaliburComponentSelector();
  -         this.setupSelector(this.modeMapping);
  -         this.setupSelector(this.outputMapping);
  -         this.manager2.addComponentInstance(Selector.ROLE + "Selector", 
this.modeMapping);
  -         this.manager2.addComponentInstance(Selector.ROLE + "Selector", 
this.outputMapping);
  -        } catch (Exception e) {
  -            getLogger().error("cannot obtain the Component", e);
  -            throw new ComponentException("cannot obtain the URLFactory", e);
  -        }
  -    }
  -
  -    private void setupSelector(
  -                            ExcaliburComponentSelector selector
  -                            ) 
  -     throws Exception 
  -    {
  -        selector.setLogger(getLogger());
  -        selector.contextualize(this.context);
  -        selector.setRoleManager(this.roleManager);
  -        selector.compose(this.manager2);
  -    }
  -
  -    public void contextualize(
  -                           Context context
  -                           ) 
  -     throws ContextException 
  -    {
  -        this.context = context;
  -    }
  -
  -    /**
  -     * Return the component manager for this sitemap
  -     */
  -    public ComponentManager getComponentManager() 
  -    {
  -        return this.manager2;
  -    }
  -
  -    /**
  -     * Release all components.
  -     */
  -    public void dispose() 
  -    {
  -        if (this.urlFactory != null) {
  -            manager.release((Component)this.urlFactory);
  -        }
  -        if (this.modeMapping != null) {
  -            manager2.release((Component)this.modeMapping);
  -     }
  -        if (this.outputMapping != null) {
  -            manager2.release((Component)this.outputMapping);
  -        }
  -     manager2.dispose();
  -    }
  -
  -
  -    /**
  -     * Configure modes that are used to delegate database specific methods
  -     * and other modes.
  +     * set all necessary ?s and execute the query
        */
  -    public void configure(
  -                       Configuration conf
  -                       ) 
  -     throws ConfigurationException 
  +    protected void processRow ( 
  +                            Request request,
  +                            Connection conn,
  +                            PreparedStatement statement,
  +                            Configuration table,
  +                            CacheHelper queryData,
  +                            Object[][] columnValues,
  +                            int rowIndex,
  +                            Map results
  +                            )
  +     throws SQLException,
  +            ConfigurationException,
  +            Exception 
       {
  -     try {
  -         getLogger().debug("MDAA: configure");
  -         LinkedList hints = new LinkedList();
  -         if (conf != null) {
  -             String val = null;
  -             String nodeName = null;
  -             Configuration[] parameters = conf.getChildren();
  -             this.settings = new HashMap(parameters.length);
  -             for ( int i = 0; i < parameters.length; i++) {
  -                 nodeName= parameters[i].getName();
  -                 getLogger().debug("configure -- " + nodeName);
  -                 if ( nodeName != null ) {
  -                     if ( "mode".equals(nodeName.trim()) || 
"output".equals(nodeName.trim())) {
  -                         String modeName = 
parameters[i].getAttribute("name");
  -                         String src = parameters[i].getAttribute("src");
  -                         if (modeName!=null && src!=null) {
  -                             Configuration modeConfig = parameters[i];
  -                             if (modeConfig == null) {
  -                                 modeConfig = this.defaultConfig;
  -                             }
  -                             getLogger().debug("load -- " + modeName + " -> 
" + src);
  -                             if ( "mode".equals(nodeName.trim())) {
  -                                 this.load_component(modeMapping, modeName, 
src, modeConfig);
  -                                 hints.add(modeName);
  -                             } else {
  -                                 this.load_component(outputMapping, 
modeName, src, modeConfig);
  -                                 if ( !defaultModeNames.containsKey( 
MODE_OUTPUT ) ) {
  -                                     defaultModeNames.put( MODE_OUTPUT, 
modeName );
  -                                 }
  -                             }
  -                         }
  -                     } else {
  -                         val = parameters[i].getValue();
  -                         this.settings.put(nodeName, val);
  -                     }
  -                 }
  -             }
  -         }
  -         
  -         this.modeMapping.initialize();
  -         this.outputMapping.initialize();
  -         this.manager2.initialize();
  -
  -         ListIterator li = hints.listIterator();
  -         while ( li.hasNext() ) {
  -             String modeName = (String) li.next();
  -             Component helper = modeMapping.select( modeName );
  -             if ( !defaultModeNames.containsKey( MODE_OTHERS ) && helper 
instanceof AttributeHelper ) { 
  -                 defaultModeNames.put( MODE_OTHERS, modeName );
  -                 getLogger().debug(modeName + " default mode for delete / 
update operations");
  -             }
  -             
  -             if ( !defaultModeNames.containsKey( MODE_INSERT ) && helper 
instanceof KeyAttributeHelper ) { 
  -                 defaultModeNames.put( MODE_INSERT, modeName );
  -                 getLogger().debug(modeName + " default mode for insert 
operations");
  -             }
  -             modeMapping.release(helper);
  -         }
        
  -         if ( !defaultModeNames.containsKey( MODE_OTHERS ) || 
  -              !defaultModeNames.containsKey( MODE_INSERT ) || 
  -              !defaultModeNames.containsKey( MODE_OUTPUT ) 
  -              ) {
  -             throw new ConfigurationException("Not all default modes are 
configured:"
  -                                              + ( 
defaultModeNames.containsKey( MODE_INSERT ) ? " insert mode" : "" )
  -                                              + ( 
defaultModeNames.containsKey( MODE_OTHERS ) ? " others" : "" )
  -                                              + ( 
defaultModeNames.containsKey( MODE_OUTPUT ) ? " output" : "" )
  -                                              );
  +     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, request, results );
  +         } else {
  +             this.setColumn( statement, currentIndex, request, 
col.columnConf, 
  +                             getOutputName( table, col.columnConf, rowIndex 
),
  +                             columnValues[ i ][ ( col.isSet ? rowIndex : 0 ) 
], 
  +                             rowIndex);
  +             currentIndex++;
            }
  -         
  -     } catch (Exception e) {
  -         throw new ConfigurationException(e.toString());
        }
  -    }
  -
  -
  -    /**
  -     * Load a component.
  -     *
  -     * @param hint Object to identify this component
  -     * @param classURL component's class name / URL
  -     * @param config configuration for this component
  -     */
  -    private void load_component( 
  -                             ExcaliburComponentSelector selector,
  -                             Object hint, 
  -                             String classURL, 
  -                             Configuration config 
  -                             ) 
  -     throws Exception 
  -    {
  -     Class clazz = null;
  -     //FIXME(GP): Is it true that a class name containing a colon should be 
an URL?
  -     if (classURL.indexOf(':') > 1) {
  -         URL url = urlFactory.getURL(classURL);
  -         byte[] b = getByteArrayFromStream(url.openStream());
  -         clazz = 
((RepositoryClassLoader)ClassUtils.getClassLoader()).defineClass(b);
  -     } else {
  -         clazz = ClassUtils.loadClass(classURL);
  -     }
  -     if (!Component.class.isAssignableFrom(clazz)) {
  -         throw new IllegalAccessException("Object " + classURL + " is not a 
Component");
  +     statement.execute();
  +     // 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, request, results );
  +         }
        }
  -     selector.addComponent(hint, clazz, config);
  -    }
  -
  -    /**
  -     * Helper to read in a class
  -     */
  -    private byte[] getByteArrayFromStream(
  -                                       InputStream stream
  -                                       ) 
  -    {
  -        List list = new ArrayList();
  -        byte[] b = new byte[BYTE_ARRAY_SIZE];
  -        int last = 0;
  -        try {
  -            while ((last = stream.read(b)) == BYTE_ARRAY_SIZE) {
  -                list.add(b);
  -                b = new byte[BYTE_ARRAY_SIZE];
  -            }
  -        } catch (IOException ioe) {
  -            getLogger().error("cannot read class byte stream", ioe);
  -        }
  -        list.add(b);
  -        int listSize = list.size();
  -        b = new byte[(listSize - 1) * BYTE_ARRAY_SIZE + last];
  -        int i;
  -        for (i = 0; i < listSize - 1; i++) {
  -            System.arraycopy(list.get(i), 0, b, i * BYTE_ARRAY_SIZE, 
BYTE_ARRAY_SIZE);
  -        }
  -        System.arraycopy(list.get(i), 0, b, i * BYTE_ARRAY_SIZE, last);
  -        return b;
       }
   
   
  -    // <==== please ignore
  -    //
  -
  -    // 
========================================================================
  -    // protected utility methods
  -    // 
========================================================================
  -
  -
  -    /**
  -     * 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;
  -      }
  -    }
  -
  -
       /**
  -     * override super's method since we prefer to get the datasource
  -     * from defaults first or from sitemap parameters rather than from 
  -     * descriptor file.
  +     * determine which mode to use as default mode
  +     * here: INSERT
  +     * highly specific to operation INSERT / UPDATE / DELETE / SELECT
        */
  -    protected DataSourceComponent getDataSource( Configuration conf, 
Parameters parameters )
  -     throws ComponentException
  +    protected String selectMode (
  +                               boolean isAutoIncrement,
  +                               HashMap modes
  +                               )
       {
  -     String sourceName = parameters.getParameter("connection", (String) 
settings.get("connection"));
  -     if ( sourceName == null ) {
  -         return getDataSource( conf );
  -     } else {
  -         getLogger().debug("Using datasource: "+sourceName);
  -         return (DataSourceComponent) this.dbselector.select(sourceName);
  -     }
  -    }
  -
  -    /**
  -     * Store a key/value pair in the request attributes. We prefix the key
  -     * with the name of this class to prevent potential name collisions.
  -     * This method overrides super class' method to allow an OutputHelper 
  -     * to take care of what to do with the values.
  -     */
  -    void setRequestAttribute(Request request, String key, Object value) {
  -     try {
  -         OutputHelper oh = (OutputHelper) outputMapping.select( (String) 
defaultModeNames.get( MODE_OUTPUT ) );
  -         oh.setAttribute(request, key, value);
  -         outputMapping.release(oh);
  -     } catch (Exception e) {
  -         getLogger()
  -             .warn( "Could not select output mode " 
  -                    + (String) defaultModeNames.get( MODE_OUTPUT ) 
  -                    + ":" + e.getMessage() );
  -     }
  +     if ( isAutoIncrement )
  +         return (String) modes.get( MODE_AUTOINCR );
  +     else 
  +         return (String) modes.get( MODE_OTHERS );
       }
   
       /**
  -     * Retrieve a value from the request attributes.
  -     * This method overrides super class' method to allow an OutputHelper 
  -     * to take care of where to get the values.
  +     * determine whether autoincrement columns should be honoured by
  +     * this operation. This is usually snsible only for INSERTs.
        */
  -    Object getRequestAttribute(Request request, String key) {
  -     Object value = null;
  -     try {
  -         OutputHelper oh = (OutputHelper) outputMapping.select( (String) 
defaultModeNames.get( MODE_OUTPUT ) );
  -         value = oh.getAttribute(request, key);
  -         outputMapping.release(oh);
  -     } catch (Exception e) {
  -         getLogger()
  -             .warn( "Could not select output mode "
  -                    + (String) defaultModeNames.get( MODE_OUTPUT )
  -                    + ":" + e.getMessage());
  -     }
  -     return value;
  -    }
  +    protected boolean honourAutoIncrement() { return true; }
   
   
  -    // 
========================================================================
  -    // main method
  -    // 
========================================================================
  -
  -
       /**
  -     * Add a record to the database.  This action assumes that
  -     * the file referenced by the "descriptor" parameter conforms
  -     * to the AbstractDatabaseAction specifications.
  +     * Fetch all values for all columns that are needed to do the
  +     * database operation.
        */
  -    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;
  -     Request request = (Request) objectModel.get(Constants.REQUEST_OBJECT);
  -
  -     getLogger().debug("MDAA: act");
  -     if (this.settings.containsKey("reloadable"))
  -         reloadable = Boolean.getBoolean((String) 
this.settings.get("reloadable"));
  -     // read local parameter settings
  -        try {
  -            Configuration conf = 
  -             this.getConfiguration(param.getParameter("descriptor", (String) 
this.settings.get("descriptor")), 
  -                                   
param.getParameterAsBoolean("reloadable",reloadable));
  -
  -            datasource = this.getDataSource(conf, param);
  -            conn = datasource.getConnection();
  -            if (conn.getAutoCommit() == true) {
  -                conn.setAutoCommit(false);
  -            }
  -
  -         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
  -         
  -         HashMap modeTypes = null;
  -
  -         if (tablesetname != null) {
  -             // new set based behaviour
  -             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");
  -             
  -             // construct a Map that contains the names of the tables
  -             // contained in the requested tableset
  -             set_tables = new HashMap(set.length);
  -             for (int i=0; i<set.length; i++) {
  -                 // look for alternative modes
  -                 modeTypes = new HashMap(2);
  -                 modeTypes.put( MODE_INSERT, set[i].getAttribute( 
"add-mode",    "insert" ) );
  -                 modeTypes.put( MODE_OTHERS, set[i].getAttribute( 
"others-mode", "others" ) );
  -                 set_tables.put(set[i].getAttribute("name",""), modeTypes);
  -             }
  -         } else {
  -             modeTypes = new HashMap(2);
  -             modeTypes.put( MODE_INSERT, "insert" );
  -             modeTypes.put( MODE_OTHERS, "others" );
  -         };
  -         for (int i=0; i<tables.length; i++) {
  -             if (set_tables == null || 
set_tables.containsKey(tables[i].getAttribute("name"))) {
  -                 if (tablesetname != null) {
  -                     modeTypes = (HashMap) 
set_tables.get(tables[i].getAttribute("name"));
  -                 }
  -                 processTable( tables[i], conn, request, results, modeTypes 
);
  -             }
  -         }
  -
  -            conn.commit();
  -         OutputHelper oh = (OutputHelper) outputMapping.select( (String) 
defaultModeNames.get( MODE_OUTPUT ) );
  -         oh.commit(request);
  -         outputMapping.release(oh);
  -        } catch (Exception e) {
  -            if (conn != null) {
  -                try {
  -                 getLogger().debug( "Rolling back transaction. Caused by " + 
e.getMessage() );
  -                    conn.rollback();
  -                 OutputHelper oh = (OutputHelper) outputMapping.select( 
(String) defaultModeNames.get( MODE_OUTPUT ) );
  -                 oh.rollback(request, e);
  -                 outputMapping.release(oh);
  -                } catch (SQLException se) {
  -                    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
  -            //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,
  -                   HashMap modeTypes
  -                   ) 
  -     throws SQLException,
  -            ConfigurationException,
  -            Exception 
  -    {
  -      PreparedStatement statement = null;
  -      try {
  -       getLogger()
  -           .debug( "i-mode: " + (String) modeTypes.get( MODE_INSERT ) +" (" 
+ (String) defaultModeNames.get( MODE_INSERT ) + ")  " +
  -                   "o-mode: " + (String) modeTypes.get( MODE_OTHERS ) +" (" 
+ (String) defaultModeNames.get( MODE_OTHERS ) + ")" );
  -       CacheHelper queryData = this.getQuery( table, modeTypes, 
defaultModeNames );
  -       getLogger().debug("query: "+queryData.queryString);
  -       statement = conn.prepareStatement(queryData.queryString);
  -
  -       if ( !queryData.isSet ) {
  -           getLogger().debug("=====> single row");
  -           processRow ( request, conn, statement, table, queryData, -1, 
null, results );
  -       } else {
  -           getLogger().debug("=====> multiple rows");
  -           if ( queryData.setMaster == -1 ) {
  -               throw new ConfigurationException( "Database description 
configuration error: Set mode without set master" );
  -           }
  -           AccessHelper dah = (AccessHelper) modeMapping.select( 
queryData.columns[ queryData.setMaster ].mode );
  -           Set vSet = dah.getAttributeSet( table.getAttribute( "name" ) 
  -                                           + "." 
  -                                           + queryData.columns[  
queryData.setMaster ].columnConf.getAttribute( "name" ), 
  -                                           queryData.columns[  
queryData.setMaster ].modeConf, 
  -                                           request );
  -           Iterator vIter = vSet.iterator();
  -           getLogger().debug("=====> set size is " + vSet.size());
  -           getLogger().debug("=====> set is empty? " + vSet.isEmpty());
  -           int rowIndex = 0;
  -           while( vIter.hasNext() ) {
  -               Object idx = vIter.next();
  -               getLogger().debug("=====> idx="+idx);
  -               processRow ( request, conn, statement, table, queryData, 
rowIndex, idx, results );
  -               rowIndex++;
  -           }
  -           modeMapping.release(dah);
  -       }
  -     
  -      } finally {
  -       try {
  -           if (statement != null) {
  -               statement.close();
  -           }
  -       } catch (SQLException e) {}
  -      }
  -    }
  -
  -    /**
  -     * Put key values to to request attributes.
  -     */
  -
  -    void storeKeyValue( 
  -                    Configuration tableConf, 
  -                    Column key,
  -                    Object idx,
  -                    int rowIndex,
  -                    Connection conn, 
  -                    Statement statement, 
  -                    Request request, 
  -                    Map results
  -                    ) 
  -     throws SQLException, 
  -            ConfigurationException, 
  -            ComponentException 
  -    {
  -     KeyAttributeHelper dah = (KeyAttributeHelper) modeMapping.select( 
key.mode );
  -     if (!dah.includeAsValue()) {
  -         String keyname = getOutputName( tableConf, key.columnConf, rowIndex 
);
  -         Object value = dah.getPostValue( tableConf, key.columnConf, 
key.modeConf, conn, statement, request );
  -         getLogger().debug( "Retrieving autoincrement as " + value );
  -         setRequestAttribute( request, keyname, value );
  -         results.put( key.columnConf.getAttribute("name"), String.valueOf( 
value ) );
  +    Object[][] getColumnValues( 
  +                          Configuration tableConf,
  +                          CacheHelper queryData,
  +                          Request request
  +                          )
  +     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], request );
        }
  -     modeMapping.release(dah);
  -    }
  -
  -    /**
  -     * compose name for output a long the lines of "table.column[row]"
  -     * or "table.column" if rowIndex is -1 
  -     */
  -    String getOutputName (
  -                       Configuration tableConf,
  -                       Configuration columnConf,
  -                       int rowIndex
  -                       )
  -     throws ConfigurationException
  -    {
  -     return 
tableConf.getAttribute("name")+"."+columnConf.getAttribute("name")+(rowIndex==-1?"":
 "["+rowIndex+"]");
  +     return columnValues;
       }
   
   
  -
  -    /**
  -     * 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, 
  -            Column column, 
  -            int currentIndex, 
  -            Object idx,
  -            int rowIndex,
  -            Connection conn, 
  -            PreparedStatement statement, 
  -            Request request, 
  -            Map results
  -            ) 
  -     throws ConfigurationException, 
  -            SQLException, 
  -            ComponentException, 
  -            Exception 
  -    {
  -      KeyAttributeHelper dah = (KeyAttributeHelper) modeMapping.select( 
column.mode );
  -      String keyname = table.getAttribute( "name" ) + '.' +
  -       column.columnConf.getAttribute( "name" ) + 
  -       ( rowIndex == -1 ? "" : "[" + rowIndex + "]" );
  -
  -      int columnCount = 0;
  -      if ( dah.includeInQuery() ) {
  -       if ( dah.includeAsValue() ) {
  -           Object value = dah.getPreValue( table, column.columnConf, 
column.modeConf, conn, request,  ( column.isSet ? idx : null ) );
  -           getLogger().debug( "Setting key " + keyname + " to " + value );
  -           statement.setObject( currentIndex, value );
  -           setRequestAttribute( request, keyname, value );
  -           results.put( column.columnConf.getAttribute( "name" ), 
String.valueOf( value ) );
  -           columnCount = 1;
  -       }
  -      } else {
  -       getLogger().debug( "Automatically setting key" );
  -      }  
  -      modeMapping.release( dah );
  -      return columnCount;
  -    }
  -
       /**
        * 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
        */
  @@ -875,7 +159,7 @@
   
                   StringBuffer queryBuffer = new StringBuffer("INSERT INTO ");
                   StringBuffer valueBuffer = new StringBuffer(") VALUES (");
  -             KeyAttributeHelper dah;
  +             AutoIncrementHelper dah;
   
                   queryBuffer.append(table.getAttribute("name"));
                   queryBuffer.append(" (");
  @@ -886,8 +170,8 @@
                        queryBuffer.append( ", " );
                        valueBuffer.append( ", " );
                    }
  -                 if ( queryData.columns[i].isKey ) {
  -                     dah = (KeyAttributeHelper) modeMapping.select( 
queryData.columns[i].mode );
  +                 if ( queryData.columns[i].isKey && 
queryData.columns[i].isAutoIncrement ) {
  +                     dah = (AutoIncrementHelper) modeMapping.select( 
queryData.columns[i].mode );
                        if ( dah.includeInQuery() ) {
                            actualColumns++;
                            queryBuffer.append( 
queryData.columns[i].columnConf.getAttribute( "name" ) );
  @@ -917,170 +201,5 @@
           return queryData;
       }
   
  -
  -    /**
  -     * Set a column based in a prepared statement by asking an 
AttributeHelper.
  -     * Delegates 'real' work to similar method in super class.
  -     */
  -    protected void setColumn(
  -                          Configuration table,
  -                          Column column,
  -                          int index,
  -                          Object idx,
  -                          int rowIndex,
  -                          PreparedStatement stmt,
  -                          Request request
  -                           ) 
  -     throws ConfigurationException, 
  -            Exception
  -    {
  -     AttributeHelper dph = (AttributeHelper) modeMapping.select( column.mode 
);
  -     Object value = dph.getValue( table.getAttribute( "name" ) + "." + 
column.columnConf.getAttribute( "name" ), 
  -                                  column.modeConf, request, ( column.isSet ? 
idx : null ) );
  -     modeMapping.release( dph );
  -     String cname = getOutputName( table, column.columnConf, rowIndex );
  -     getLogger().debug( "Setting column " + cname + " to " + value +" using 
index " + idx );
  -     this.setColumn( stmt, index, request, column.columnConf, cname, value,  
rowIndex );
  -    }
  -
  -
  -    /**
  -     * set all necessary ?s and execute the query
  -     */
  -    protected void processRow ( 
  -                            Request request,
  -                            Connection conn,
  -                            PreparedStatement statement,
  -                            Configuration table,
  -                            CacheHelper queryData,
  -                            int rowIndex,
  -                            Object idx,
  -                            Map results
  -                            )
  -     throws SQLException,
  -            ConfigurationException,
  -            Exception 
  -    {
  -     
  -     int currentIndex = 1;
  -     for (int i = 0; i < queryData.columns.length; i++) {
  -         if ( queryData.columns[i].isKey ) {
  -             currentIndex += setKey( table, queryData.columns[i], 
currentIndex, idx, rowIndex, 
  -                                     conn, statement, request, results );
  -         } else {
  -             this.setColumn( table, queryData.columns[i], currentIndex, idx, 
rowIndex, 
  -                             statement, request );
  -             currentIndex++;
  -         }
  -     }
  -     statement.execute();
  -     // get resulting ids
  -     for (int i = 0; i < queryData.columns.length; i++) {
  -         if ( queryData.columns[i].isKey ) {
  -             storeKeyValue( table, queryData.columns[i], idx, rowIndex, 
  -                            conn, statement, request, results );
  -         }
  -     }
  -    }
  -
  -
  -    
  -    /**
  -     * Setup parsed attribute configuration object
  -     */
  -    protected void fillModes ( Configuration[] conf,
  -                            boolean isKey,
  -                            HashMap defaultModeNames,
  -                            HashMap modeTypes,
  -                            CacheHelper set
  -                            )
  -     throws ConfigurationException
  -    {
  -     String setMode = null;
  -     int setMaster = -1;
  -     String setMastersMode = null;
  -     boolean manyrows = false;
  -     int offset = ( isKey ? 0: set.noOfKeys);
  -
  -     getLogger().debug("isKey="+(isKey?"true":"false")+" 
set.columns.length="+set.columns.length);
  -     getLogger().debug(set.columns[0].getClass().getName());
  -
  -        for ( int i = offset; i < conf.length + offset; i++ ) {
  -         getLogger().debug("i="+i);
  -         set.columns[i].columnConf =  conf[ i - offset ];
  -         set.columns[i].modeConf = getMode( set.columns[i].columnConf, 
selectMode( isKey, modeTypes ) );
  -         set.columns[i].mode = ( set.columns[i].modeConf != null ? 
  -                                 set.columns[i].modeConf.getAttribute( 
"name", selectMode( isKey, defaultModeNames ) ) :  selectMode( isKey, 
defaultModeNames ) );
  -         set.columns[i].isSet = false;
  -         set.columns[i].isKey = isKey;
  -         // 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;
  -             }
  -         } 
  -     }
  -    }
  -
  -
  -    /**
  -     * determine which mode to use as default mode
  -     * here: INSERT
  -     * highly specific to operation INSERT / UPDATE / DELETE / SELECT
  -     */
  -
  -    protected String selectMode (
  -                               boolean isKeyColumns,
  -                               HashMap modes
  -                               )
  -    {
  -     if (isKeyColumns)
  -         return (String) modes.get( MODE_INSERT );
  -     else 
  -         return (String) modes.get( MODE_OTHERS );
  -    }
  -
  -
  -
  -    /**
  -     * 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. Known types are "insert", used for 
key columns
  -     * when new data is inserted, "others" used for all other situations 
(i.e. non key
  -     * columns or non insert operations with key columns). 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");
  -         getLogger().debug("requested mode is \""+type+"\" found 
\""+modeType+"\"");
  -         if ( modeType.equals(type) || modeType.equals(modeAll)) {
  -             getLogger().debug("returning "+modeType);
  -             modeConfig = modes[i];
  -             break;
  -         };
  -     }
  -
  -     return modeConfig;
  -    }
   
   }
  
  
  
  1.2       +42 -14    
xml-cocoon2/scratchpad/src/org/apache/cocoon/acting/ModularDatabaseDeleteAction.java
  
  Index: ModularDatabaseDeleteAction.java
  ===================================================================
  RCS file: 
/home/cvs/xml-cocoon2/scratchpad/src/org/apache/cocoon/acting/ModularDatabaseDeleteAction.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ModularDatabaseDeleteAction.java  2001/11/19 16:28:33     1.1
  +++ ModularDatabaseDeleteAction.java  2001/11/23 10:50:35     1.2
  @@ -28,10 +28,10 @@
    * @author <a href="mailto:[EMAIL PROTECTED]">Berin Loritsch</a>
    * @author <a href="mailto:[EMAIL PROTECTED]">Donald Ball</a>
    * @author <a href="mailto:[EMAIL PROTECTED]">Christian Haul</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2001/11/19 16:28:33 $
  + * @version CVS $Revision: 1.2 $ $Date: 2001/11/23 10:50:35 $
    */
   public class ModularDatabaseDeleteAction 
  -    extends ModularDatabaseAddAction
  +    extends ModularDatabaseAction
   {
   
       /**
  @@ -41,7 +41,7 @@
        */
   
       protected String selectMode (
  -                               boolean isKeyColumns,
  +                               boolean isAutoIncrement,
                                  HashMap modes
                                  )
       {
  @@ -49,7 +49,38 @@
       }
   
   
  +    /**
  +     * 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.
  +     */
  +    Object[][] getColumnValues( 
  +                          Configuration tableConf,
  +                          CacheHelper queryData,
  +                          Request request
  +                          )
  +     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], request );
  +         } 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,
  @@ -106,8 +137,8 @@
                               PreparedStatement statement,
                               Configuration table,
                               CacheHelper queryData,
  +                            Object[][] columnValues,
                               int rowIndex,
  -                            Object idx,
                               Map results
                               )
        throws SQLException,
  @@ -119,19 +150,16 @@
   
        // ordering is different for DELETE just needs keys
        for (int i = 0; i < queryData.columns.length; i++) {
  -         if ( queryData.columns[i].isKey ) {
  -             currentIndex += setKey( table, queryData.columns[i], 
currentIndex, idx, rowIndex,
  -                                     conn, statement, request, results );
  +         Column col = queryData.columns[i];
  +         if ( col.isKey ) {
  +             this.setColumn( statement, currentIndex, request, 
col.columnConf, 
  +                             getOutputName( table, col.columnConf, rowIndex 
),
  +                             columnValues[ i ][ ( col.isSet ? rowIndex : 0 ) 
], 
  +                             rowIndex);
  +             currentIndex++;
            }
        }
        statement.execute();
  -     // get resulting ids
  -     for (int i = 0; i < queryData.columns.length; i++) {
  -         if ( queryData.columns[i].isKey ) {
  -             storeKeyValue( table, queryData.columns[i], idx, rowIndex,
  -                            conn, statement, request, results );
  -         }
  -     }
       }
   
   }
  
  
  
  1.2       +41 -12    
xml-cocoon2/scratchpad/src/org/apache/cocoon/acting/ModularDatabaseSelectAction.java
  
  Index: ModularDatabaseSelectAction.java
  ===================================================================
  RCS file: 
/home/cvs/xml-cocoon2/scratchpad/src/org/apache/cocoon/acting/ModularDatabaseSelectAction.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ModularDatabaseSelectAction.java  2001/11/19 16:28:33     1.1
  +++ ModularDatabaseSelectAction.java  2001/11/23 10:50:35     1.2
  @@ -36,10 +36,10 @@
    * @author <a href="mailto:[EMAIL PROTECTED]">Berin Loritsch</a>
    * @author <a href="mailto:[EMAIL PROTECTED]">Donald Ball</a>
    * @author <a href="mailto:[EMAIL PROTECTED]">Christian Haul</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2001/11/19 16:28:33 $
  + * @version CVS $Revision: 1.2 $ $Date: 2001/11/23 10:50:35 $
    */
   public class ModularDatabaseSelectAction 
  -    extends ModularDatabaseAddAction
  +    extends ModularDatabaseAction
   {
   
       /**
  @@ -49,7 +49,7 @@
        */
   
       protected String selectMode (
  -                               boolean isKeyColumns,
  +                               boolean isAutoIncrement,
                                  HashMap modes
                                  )
       {
  @@ -57,7 +57,13 @@
       }
   
   
  +    /**
  +     * 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,
  @@ -122,6 +128,30 @@
   
   
       /**
  +     * Fetch all values for all key columns that are needed to do the
  +     * database operation.
  +     */
  +    Object[][] getColumnValues( 
  +                          Configuration tableConf,
  +                          CacheHelper queryData,
  +                          Request request
  +                          )
  +     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], request );
  +         } else {
  +             // columnValues[i] = new Object[1]; // this should not be needed
  +         }
  +     }
  +     return columnValues;
  +    }
  +
  +
  +    /**
        * set all necessary ?s and execute the query
        */
       protected void processRow ( 
  @@ -130,8 +160,8 @@
                               PreparedStatement statement,
                               Configuration table,
                               CacheHelper queryData,
  +                            Object[][] columnValues,
                               int rowIndex,
  -                            Object idx,
                               Map results
                               )
        throws SQLException,
  @@ -143,17 +173,16 @@
   
        // ordering is different for SELECT just needs keys
        for (int i = 0; i < queryData.columns.length; i++) {
  -         if ( queryData.columns[i].isKey ) {
  -             currentIndex += setKey( table, queryData.columns[i], 
currentIndex, idx, rowIndex,
  -                                     conn, statement, request, results );
  +         Column col = queryData.columns[i];
  +         if ( col.isKey ) {
  +             this.setColumn( statement, currentIndex, request, 
col.columnConf, 
  +                             getOutputName( table, col.columnConf, rowIndex 
),
  +                             columnValues[ i ][ ( col.isSet ? rowIndex : 0 ) 
], 
  +                             rowIndex);
  +             currentIndex++;
            }
        }
        statement.execute();
  -     // get resulting ids
  -     for (int i = 0; i < queryData.columns.length; i++) {
  -         storeKeyValue( table, queryData.columns[i], idx, rowIndex, 
  -                        conn, statement, request, results );
  -     }
        // retrieve values
        ResultSet resultset = statement.getResultSet();
        rowIndex = -1;
  
  
  
  1.2       +43 -17    
xml-cocoon2/scratchpad/src/org/apache/cocoon/acting/ModularDatabaseUpdateAction.java
  
  Index: ModularDatabaseUpdateAction.java
  ===================================================================
  RCS file: 
/home/cvs/xml-cocoon2/scratchpad/src/org/apache/cocoon/acting/ModularDatabaseUpdateAction.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ModularDatabaseUpdateAction.java  2001/11/19 16:28:33     1.1
  +++ ModularDatabaseUpdateAction.java  2001/11/23 10:50:35     1.2
  @@ -28,10 +28,10 @@
    * @author <a href="mailto:[EMAIL PROTECTED]">Berin Loritsch</a>
    * @author <a href="mailto:[EMAIL PROTECTED]">Donald Ball</a>
    * @author <a href="mailto:[EMAIL PROTECTED]">Christian Haul</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2001/11/19 16:28:33 $
  + * @version CVS $Revision: 1.2 $ $Date: 2001/11/23 10:50:35 $
    */
   public class ModularDatabaseUpdateAction 
  -    extends ModularDatabaseAddAction
  +    extends ModularDatabaseAction
   {
   
       /**
  @@ -41,7 +41,7 @@
        */
   
       protected String selectMode (
  -                               boolean isKeyColumns,
  +                               boolean isAutoIncrement,
                                  HashMap modes
                                  )
       {
  @@ -49,7 +49,33 @@
       }
   
   
  +    /**
  +     * 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.
  +     */
  +    Object[][] getColumnValues( 
  +                          Configuration tableConf,
  +                          CacheHelper queryData,
  +                          Request request
  +                          )
  +     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], request );
  +     }
  +     return columnValues;
  +    }
   
  +
       /**
        * Get the String representation of the PreparedStatement.  This is
        * mapped to the Configuration object itself, so if it doesn't exist,
  @@ -125,8 +151,8 @@
                               PreparedStatement statement,
                               Configuration table,
                               CacheHelper queryData,
  +                            Object[][] columnValues,
                               int rowIndex,
  -                            Object idx,
                               Map results
                               )
        throws SQLException,
  @@ -138,26 +164,26 @@
   
        // ordering is different for UPDATE than for INSERT: values, keys
        for (int i = 0; i < queryData.columns.length; i++) {
  -         if ( !queryData.columns[i].isKey ) {
  -             this.setColumn( table, queryData.columns[i], currentIndex, idx, 
rowIndex,
  -                             statement, request );
  +         Column col = queryData.columns[i];
  +         if ( !col.isKey ) {
  +             this.setColumn( statement, currentIndex, request, 
col.columnConf, 
  +                             getOutputName( table, col.columnConf, rowIndex 
),
  +                             columnValues[ i ][ ( col.isSet ? rowIndex : 0 ) 
], 
  +                             rowIndex);
                currentIndex++;
            }
        }
        for (int i = 0; i < queryData.columns.length; i++) {
  -         if ( queryData.columns[i].isKey ) {
  -             currentIndex += setKey( table, queryData.columns[i], 
currentIndex, idx, rowIndex,
  -                                     conn, statement, request, results );
  +         Column col = queryData.columns[i];
  +         if ( col.isKey ) {
  +             this.setColumn( statement, currentIndex, request, 
col.columnConf, 
  +                             getOutputName( table, col.columnConf, rowIndex 
),
  +                             columnValues[ i ][ ( col.isSet ? rowIndex : 0 ) 
], 
  +                             rowIndex);
  +             currentIndex++;
            }
        }
        statement.execute();
  -     // get resulting ids
  -     for (int i = 0; i < queryData.columns.length; i++) {
  -         if ( queryData.columns[i].isKey ) {
  -             storeKeyValue( table, queryData.columns[i], idx, rowIndex,
  -                            conn, statement, request, results );
  -         }
  -     }
       }
   
   }
  
  
  
  1.1                  
xml-cocoon2/scratchpad/src/org/apache/cocoon/acting/ModularDatabaseAction.java
  
  Index: ModularDatabaseAction.java
  ===================================================================
  /*****************************************************************************
   * Copyright (C) The Apache Software Foundation. All rights reserved.        *
   * ------------------------------------------------------------------------- *
   * This software is published under the terms of the Apache Software License *
   * version 1.1, a copy of which has been included  with this distribution in *
   * the LICENSE file.                                                         *
   
*****************************************************************************/
  package org.apache.cocoon.acting;
  
  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.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.thread.ThreadSafe;
  import org.apache.avalon.excalibur.component.ExcaliburComponentSelector;
  import org.apache.avalon.excalibur.component.ExcaliburComponentManager;
  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.components.url.URLFactory;
  import org.apache.cocoon.environment.Request;
  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.selection.Selector;
  
  import org.apache.cocoon.acting.ModularDatabaseAccess.AutoIncrementHelper;
  import org.apache.cocoon.acting.ModularDatabaseAccess.AttributeHelper;
  import org.apache.cocoon.acting.ModularDatabaseAccess.OutputHelper;
  
  /**
   * 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. 
   *
   * The difference to the other Database*Actions is, that it uses
   * additional components for reading and writing parameters. In
   * addition the descriptor format has changed to accomodate the new
   * features.
   *
   * This action is heavily based upon the DatabaseAddAction and relies
   * on the AbstractDatabaseAction.
   *
   * Configuration options:
   * descriptor       file containing database description
   * throw-exception  throw an exception when an error occurs (default: false)
   *
   * Note: Component management will move to sitemap so that other
   * components can utilize the helper components.
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Christian Haul</a>
   * @version CVS $Revision: 1.1 $ $Date: 2001/11/23 10:50:35 $
   */
  public abstract class ModularDatabaseAction 
      extends AbstractDatabaseAction 
      implements Disposable, ThreadSafe, Contextualizable
  {
  
      // 
========================================================================
      // inner helper classes
      // 
========================================================================
  
      protected class Column {
        boolean isKey = false;
        boolean isSet = false;
        boolean isAutoIncrement = false;
        String mode = null;
        Configuration modeConf = null;
        Configuration columnConf = null;
      }
  
      protected class CacheHelper {
        public String queryString = null;
        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();
              }
        }
      }
  
  
      protected class LookUpKey {
        public Configuration tableConf = null;
        public Map modeTypes = null;
        
        public LookUpKey( Configuration tableConf, Map modeTypes ) {
            this.tableConf = tableConf;
            this.modeTypes = modeTypes;
        }
      }
  
      // 
========================================================================
      // constants
      // 
========================================================================
  
      private static final String LOCATION = 
"org.apache.cocoon.acting.ModularDatabaseAddAction";
      private static final int BYTE_ARRAY_SIZE = 1024;
  
      static final Integer MODE_AUTOINCR = new Integer( 0 );
      static final Integer MODE_OTHERS = new Integer( 1 );
      static final Integer MODE_OUTPUT = new Integer( 2 );
  
      // 
========================================================================
      // instance vars
      // 
========================================================================
  
      // please ignore component management as I know this is ugly and I
      // hope that this duty is taken by the sitemap in short term.
      // please ignore ====>
      protected RoleManager roleManager;
      private Configuration defaultConfig;
  
      protected Context context;
  
      /** The component manager instance */
      protected ExcaliburComponentManager manager2;
  
      /** The URLFactory instance */
      protected URLFactory urlFactory;
  
      protected ExcaliburComponentSelector  modeMapping = null;
      protected ExcaliburComponentSelector  outputMapping = null;
  
      // default modes for other / insert operations
      protected HashMap defaultModeNames = new HashMap( 3 );
  
      // <==== please ignore
      //
  
      protected final Map cachedQueryData = new HashMap();
  
  
      //
      // please ignore ====>
  
      // 
========================================================================
      // setup / class loading
      // (basically copied from AbstractSitemap)
      // This is ugly. Please ignore. Helpers should be handled at sitemap level
      // so that other components can share them.
      // 
========================================================================
  
      /**
       * Set the role manager
       */
      public void setRoleManager( 
                               RoleManager roles, 
                               Configuration config
                               ) 
      {
          this.roleManager = roles;
          this.defaultConfig = config;
      }
  
      /**
       * Set the current <code>ComponentManager</code> instance used by this
       * <code>Composable</code>.
       */
      public void compose( 
                        ComponentManager manager
                        ) 
        throws ComponentException 
      {
        super.compose( manager );
        getLogger().debug("compose");
          this.manager2 = new ExcaliburComponentManager(manager);
          this.manager2.setLogger(getLogger());
          this.manager2.contextualize(this.context);
          this.manager2.setRoleManager(this.roleManager);
  
        try {
            if (this.defaultConfig != null) {
                this.manager2.configure(this.defaultConfig);
            }
            this.urlFactory = (URLFactory)manager.lookup(URLFactory.ROLE);
            this.modeMapping = new ExcaliburComponentSelector();
            this.outputMapping = new ExcaliburComponentSelector();
            this.setupSelector(this.modeMapping);
            this.setupSelector(this.outputMapping);
            this.manager2.addComponentInstance(Selector.ROLE + "Selector", 
this.modeMapping);
            this.manager2.addComponentInstance(Selector.ROLE + "Selector", 
this.outputMapping);
          } catch (Exception e) {
              getLogger().error("cannot obtain the Component", e);
              throw new ComponentException("cannot obtain the URLFactory", e);
          }
      }
  
      private void setupSelector(
                               ExcaliburComponentSelector selector
                               ) 
        throws Exception 
      {
          selector.setLogger(getLogger());
          selector.contextualize(this.context);
          selector.setRoleManager(this.roleManager);
          selector.compose(this.manager2);
      }
  
      public void contextualize(
                              Context context
                              ) 
        throws ContextException 
      {
          this.context = context;
      }
  
      /**
       * Return the component manager for this sitemap
       */
      public ComponentManager getComponentManager() 
      {
          return this.manager2;
      }
  
      /**
       * Release all components.
       */
      public void dispose() 
      {
          if (this.urlFactory != null) {
              manager.release((Component)this.urlFactory);
          }
          if (this.modeMapping != null) {
              manager2.release((Component)this.modeMapping);
        }
          if (this.outputMapping != null) {
              manager2.release((Component)this.outputMapping);
          }
        manager2.dispose();
      }
  
  
      /**
       * Configure modes that are used to delegate database specific methods
       * and other modes.
       */
      public void configure(
                          Configuration conf
                          ) 
        throws ConfigurationException 
      {
        try {
            getLogger().debug("MDAA: configure");
            LinkedList hints = new LinkedList();
            if (conf != null) {
                String val = null;
                String nodeName = null;
                Configuration[] parameters = conf.getChildren();
                this.settings = new HashMap(parameters.length);
                for ( int i = 0; i < parameters.length; i++) {
                    nodeName= parameters[i].getName();
                    getLogger().debug("configure -- " + nodeName);
                    if ( nodeName != null ) {
                        if ( "mode".equals(nodeName.trim()) || 
"output".equals(nodeName.trim())) {
                            String modeName = 
parameters[i].getAttribute("name");
                            String src = parameters[i].getAttribute("src");
                            if (modeName!=null && src!=null) {
                                Configuration modeConfig = parameters[i];
                                if (modeConfig == null) {
                                    modeConfig = this.defaultConfig;
                                }
                                getLogger().debug("load -- " + modeName + " -> 
" + src);
                                if ( "mode".equals(nodeName.trim())) {
                                    this.load_component(modeMapping, modeName, 
src, modeConfig);
                                    hints.add(modeName);
                                } else {
                                    this.load_component(outputMapping, 
modeName, src, modeConfig);
                                    if ( !defaultModeNames.containsKey( 
MODE_OUTPUT ) ) {
                                        defaultModeNames.put( MODE_OUTPUT, 
modeName );
                                    }
                                }
                            }
                        } else {
                            val = parameters[i].getValue();
                            this.settings.put(nodeName, val);
                        }
                    }
                }
            }
            
            this.modeMapping.initialize();
            this.outputMapping.initialize();
            this.manager2.initialize();
  
            ListIterator li = hints.listIterator();
            while ( li.hasNext() ) {
                String modeName = (String) li.next();
                Component helper = modeMapping.select( modeName );
                if ( !defaultModeNames.containsKey( MODE_OTHERS ) && helper 
instanceof AttributeHelper ) { 
                    defaultModeNames.put( MODE_OTHERS, modeName );
                    getLogger().debug(modeName + " default mode for normal 
columns");
                }
                
                if ( !defaultModeNames.containsKey( MODE_AUTOINCR ) && helper 
instanceof AutoIncrementHelper ) { 
                    defaultModeNames.put( MODE_AUTOINCR, modeName );
                    getLogger().debug(modeName + " default mode for 
autoincrement columns");
                }
                modeMapping.release(helper);
            }
        
            if ( !defaultModeNames.containsKey( MODE_OTHERS ) || 
                 !defaultModeNames.containsKey( MODE_AUTOINCR ) || 
                 !defaultModeNames.containsKey( MODE_OUTPUT ) 
                 ) {
                throw new ConfigurationException("Not all default modes are 
configured:"
                                                 + ( 
defaultModeNames.containsKey( MODE_AUTOINCR ) ? " insert mode" : "" )
                                                 + ( 
defaultModeNames.containsKey( MODE_OTHERS ) ? " others" : "" )
                                                 + ( 
defaultModeNames.containsKey( MODE_OUTPUT ) ? " output" : "" )
                                                 );
            }
            
        } catch (Exception e) {
            throw new ConfigurationException(e.toString());
        }
      }
  
  
      /**
       * Load a component.
       *
       * @param hint Object to identify this component
       * @param classURL component's class name / URL
       * @param config configuration for this component
       */
      private void load_component( 
                                ExcaliburComponentSelector selector,
                                Object hint, 
                                String classURL, 
                                Configuration config 
                                ) 
        throws Exception 
      {
        Class clazz = null;
        //FIXME(GP): Is it true that a class name containing a colon should be 
an URL?
        if (classURL.indexOf(':') > 1) {
            URL url = urlFactory.getURL(classURL);
            byte[] b = getByteArrayFromStream(url.openStream());
            clazz = 
((RepositoryClassLoader)ClassUtils.getClassLoader()).defineClass(b);
        } else {
            clazz = ClassUtils.loadClass(classURL);
        }
        if (!Component.class.isAssignableFrom(clazz)) {
            throw new IllegalAccessException("Object " + classURL + " is not a 
Component");
        }
        selector.addComponent(hint, clazz, config);
      }
  
      /**
       * Helper to read in a class
       */
      private byte[] getByteArrayFromStream(
                                          InputStream stream
                                          ) 
      {
          List list = new ArrayList();
          byte[] b = new byte[BYTE_ARRAY_SIZE];
          int last = 0;
          try {
              while ((last = stream.read(b)) == BYTE_ARRAY_SIZE) {
                  list.add(b);
                  b = new byte[BYTE_ARRAY_SIZE];
              }
          } catch (IOException ioe) {
              getLogger().error("cannot read class byte stream", ioe);
          }
          list.add(b);
          int listSize = list.size();
          b = new byte[(listSize - 1) * BYTE_ARRAY_SIZE + last];
          int i;
          for (i = 0; i < listSize - 1; i++) {
              System.arraycopy(list.get(i), 0, b, i * BYTE_ARRAY_SIZE, 
BYTE_ARRAY_SIZE);
          }
          System.arraycopy(list.get(i), 0, b, i * BYTE_ARRAY_SIZE, last);
          return b;
      }
  
  
      // <==== please ignore
      //
  
      // 
========================================================================
      // protected utility methods
      // 
========================================================================
  
      /**
       * override super's method since we prefer to get the datasource
       * from defaults first or from sitemap parameters rather than from 
       * descriptor file.
       */
      protected DataSourceComponent getDataSource( Configuration conf, 
Parameters parameters )
        throws ComponentException
      {
        String sourceName = parameters.getParameter( "connection", (String) 
settings.get( "connection" ) );
        if ( sourceName == null ) {
            return getDataSource( conf );
        } else {
            getLogger().debug("Using datasource: "+sourceName);
            return (DataSourceComponent) this.dbselector.select(sourceName);
        }
      }
  
      /**
       * Store a key/value pair in the request attributes. We prefix the key
       * with the name of this class to prevent potential name collisions.
       * This method overrides super class' method to allow an OutputHelper 
       * to take care of what to do with the values.
       */
      void setRequestAttribute(Request request, String key, Object value) {
        try {
            OutputHelper oh = (OutputHelper) outputMapping.select( (String) 
defaultModeNames.get( MODE_OUTPUT ) );
            oh.setAttribute( null, request, key, value );
            outputMapping.release( oh );
        } catch (Exception e) {
            getLogger()
                .warn( "Could not select output mode " 
                       + (String) defaultModeNames.get( MODE_OUTPUT ) 
                       + ":" + e.getMessage() );
        }
      }
  
      /**
       * Retrieve a value from the request attributes.
       * This method overrides super class' method to allow an OutputHelper 
       * to take care of where to get the values.
       */
      Object getRequestAttribute(Request request, String key) {
        Object value = null;
        try {
            OutputHelper oh = (OutputHelper) outputMapping.select( (String) 
defaultModeNames.get( MODE_OUTPUT ) );
            value = oh.getAttribute( null, request, key );
            outputMapping.release( oh );
        } catch (Exception e) {
            getLogger()
                .warn( "Could not select output mode "
                       + (String) defaultModeNames.get( MODE_OUTPUT )
                       + ":" + e.getMessage());
        }
        return 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();
  
        // read global parameter settings
        boolean reloadable = Constants.DESCRIPTOR_RELOADABLE_DEFAULT;
        Request request = (Request) objectModel.get(Constants.REQUEST_OBJECT);
  
        if (this.settings.containsKey("reloadable"))
            reloadable = Boolean.getBoolean((String) 
this.settings.get("reloadable"));
        // read local parameter settings
          try {
              Configuration conf = 
                this.getConfiguration(param.getParameter("descriptor", (String) 
this.settings.get("descriptor")), 
                                      
param.getParameterAsBoolean("reloadable",reloadable));
  
              datasource = this.getDataSource(conf, param);
              conn = datasource.getConnection();
              if (conn.getAutoCommit() == true) {
                  conn.setAutoCommit(false);
              }
  
            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
            
            HashMap modeTypes = null;
  
            if (tablesetname != null) {
                // new set based behaviour
                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");
                
                // construct a Map that contains the names of the tables
                // contained in the requested tableset
                set_tables = new HashMap(set.length);
                for (int i=0; i<set.length; i++) {
                    // look for alternative modes
                    modeTypes = new HashMap(2);
                    modeTypes.put( MODE_AUTOINCR, set[i].getAttribute( 
"autoincr-mode", "autoincr" ) );
                    modeTypes.put( MODE_OTHERS, set[i].getAttribute( 
"others-mode",   "others" ) );
                    set_tables.put(set[i].getAttribute("name",""), modeTypes);
                }
            } else {
                modeTypes = new HashMap(2);
                modeTypes.put( MODE_AUTOINCR, "autoincr" );
                modeTypes.put( MODE_OTHERS, "others" );
            };
            for (int i=0; i<tables.length; i++) {
                if (set_tables == null || 
set_tables.containsKey(tables[i].getAttribute("name"))) {
                    if (tablesetname != null) {
                        modeTypes = (HashMap) 
set_tables.get(tables[i].getAttribute("name"));
                    }
                    processTable( tables[i], conn, request, results, modeTypes 
);
                }
            }
  
              conn.commit();
            OutputHelper oh = (OutputHelper) outputMapping.select( (String) 
defaultModeNames.get( MODE_OUTPUT ) );
            oh.commit( null, request );
            outputMapping.release( oh );
          } catch (Exception e) {
              if ( conn != null ) {
                  try {
                    getLogger().debug( "Rolling back transaction. Caused by " + 
e.getMessage() );
                      conn.rollback();
                    OutputHelper oh = (OutputHelper) outputMapping.select( 
(String) defaultModeNames.get( MODE_OUTPUT ) );
                    oh.rollback( null, request, e );
                    outputMapping.release( oh );
                  } catch (SQLException se) {
                      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);
          }
  
          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,
                      HashMap modeTypes
                      ) 
        throws SQLException,
               ConfigurationException,
               Exception 
      {
        PreparedStatement statement = null;
        try {
          CacheHelper queryData = this.getQuery( table, modeTypes, 
defaultModeNames );
          getLogger().debug("query: "+queryData.queryString);
          statement = conn.prepareStatement(queryData.queryString);
  
          Object[][] columnValues = this.getColumnValues( table, queryData, 
request );
  
          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++ ) {
              getLogger().debug( "====> row no. " + rowIndex );
              processRow( request, conn, statement, table, queryData, 
columnValues, rowIndex, results );
          }
  
        } finally {
          try {
              if (statement != null) {
                  statement.close();
              }
          } catch (SQLException e) {}
        }
      }
  
      /**
       * 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)) {
                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"
       */
      String getOutputName (
                          Configuration tableConf,
                          Configuration columnConf
                          )
        throws ConfigurationException
      {
        return getOutputName( tableConf, columnConf, -1 );
      }
  
  
      /**
       * compose name for output a long the lines of "table.column[row]" or
       * "table.column" if rowIndex is -1.
       */
      String getOutputName (
                          Configuration tableConf,
                          Configuration columnConf,
                          int rowIndex
                          )
        throws ConfigurationException
      {
        return ( tableConf.getAttribute("alias", tableConf.getAttribute("name") 
) 
                 + "." + columnConf.getAttribute("name") 
                 + ( rowIndex == -1 ? "" : "[" + rowIndex + "]" ) );
      }
  
  
      /*
       * Read all values for a column from an AttributeHelper
       *
       * 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.
       *
       */
      Object[] getColumnValue( 
                            Configuration tableConf,
                            Column column,
                            Request request
                            )
        throws ConfigurationException,
               ComponentException
      {
        if ( column.isAutoIncrement ) {
            return new Object[1];
        } else {
            Object[] values;
            AttributeHelper dph = (AttributeHelper) modeMapping.select( 
column.mode );
            String cname = getOutputName( tableConf, column.columnConf );
            if ( column.isSet ){
                getLogger().debug( "Trying to set column " + cname +" using 
getAttributeValues method");
                values = dph.getAttributeValues( cname, column.modeConf, 
request );
            } else {
                getLogger().debug( "Trying to set column " + cname +" using 
getAttribute method");
                values = new Object[1];
                values[0] = dph.getAttribute( cname, column.modeConf, request );
            }
            modeMapping.release( dph );
            if ( values != null ) {
                for ( int i = 0; i < values.length; i++ ) {
                    getLogger().debug( "Setting column " + cname + " [" + i + 
"] " + values[i] );
                }
            }
            return values;
        }
      }
  
  
      /**
       * Setup parsed attribute configuration object
       */
      protected void fillModes ( Configuration[] conf,
                               boolean isKey,
                               HashMap defaultModeNames,
                               HashMap 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++ ) {
            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() ) {
                String autoIncrement = 
set.columns[i].columnConf.getAttribute("autoincrement","false");
                if ( autoIncrement.equalsIgnoreCase("yes") || 
autoIncrement.equalsIgnoreCase("true") ) {
                    set.columns[i].isAutoIncrement = true;
                }
            }
            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;
                }
            } 
        }
      }
  
  
  
      /**
       * Put key values into request attributes.
       */
      void storeKeyValue( 
                       Configuration tableConf, 
                       Column key,
                       int rowIndex,
                       Connection conn, 
                       Statement statement, 
                       Request request, 
                       Map results
                       ) 
        throws SQLException, 
               ConfigurationException, 
               ComponentException 
      {
        AutoIncrementHelper dah = (AutoIncrementHelper) modeMapping.select( 
key.mode );
        if (!dah.includeAsValue()) {
            String keyname = getOutputName( tableConf, key.columnConf, rowIndex 
);
            Object value = dah.getPostValue( tableConf, key.columnConf, 
key.modeConf, conn, statement, request );
            getLogger().debug( "Retrieving autoincrement for " + keyname + "as 
" + value );
            setRequestAttribute( request, keyname, value );
            results.put( keyname, String.valueOf( value ) );
        }
        modeMapping.release(dah);
      }
  
  
      /**
       * 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 request the request object
       * @param result sitemap result object
       * @return the number of columns by which to increment the currentIndex
       */
      int setKeyAuto (
                    Configuration table, 
                    Column column, 
                    int currentIndex, 
                    int rowIndex,
                    Connection conn, 
                    PreparedStatement statement, 
                    Request request, 
                    Map results
                    ) 
        throws ConfigurationException, 
               SQLException, 
               ComponentException, 
               Exception 
      {
  
        int columnCount = 0;
  
        AutoIncrementHelper dah = (AutoIncrementHelper) modeMapping.select( 
column.mode );
        if ( dah.includeInQuery() ) {
          if ( dah.includeAsValue() ) {
              Object value = dah.getPreValue( table, column.columnConf, 
column.modeConf, conn, request );
              String keyname = this.getOutputName( table, column.columnConf, 
rowIndex );
              getLogger().debug( "Setting key " + keyname + " to " + value );
              statement.setObject( currentIndex, value );
              setRequestAttribute( request, keyname, value );
              results.put( keyname, String.valueOf( value ) );
              columnCount = 1;
          }
        } else {
          getLogger().debug( "Automatically setting key" );
        }  
        modeMapping.release( dah );
        return columnCount;
      }
  
      // 
========================================================================
      // abstract methods
      // 
========================================================================
  
  
      /**
       * set all necessary ?s and execute the query
       *
       * This method is intended to be overridden by classes that
       * implement other operations e.g. delete
       */
      protected abstract void processRow( 
                                       Request request,
                                       Connection conn,
                                       PreparedStatement statement,
                                       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,
                                         HashMap 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,
                                        Request request
                                        )
        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,
                                            HashMap modeTypes,
                                            HashMap defaultModeNames
                                            ) 
        throws ConfigurationException, 
               ComponentException;
  }
  
  
  
  1.2       +3 -3      
xml-cocoon2/scratchpad/src/org/apache/cocoon/acting/ModularDatabaseAccess/AbstractAttributeHelper.java
  
  Index: AbstractAttributeHelper.java
  ===================================================================
  RCS file: 
/home/cvs/xml-cocoon2/scratchpad/src/org/apache/cocoon/acting/ModularDatabaseAccess/AbstractAttributeHelper.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- AbstractAttributeHelper.java      2001/11/19 16:28:33     1.1
  +++ AbstractAttributeHelper.java      2001/11/23 10:50:36     1.2
  @@ -13,15 +13,15 @@
   import org.apache.avalon.framework.configuration.ConfigurationException;
   import org.apache.avalon.framework.logger.AbstractLoggable;
   
  -import java.util.HashMap;
  +import org.apache.cocoon.util.HashMap;
   
   /**
    * AbstractDatabaseHelper gives you the infrastructure for easily
  - * deploying more database access helpers.  In order to get at the
  + * deploying more Attributehelpers.  In order to get at the
    * Logger, use getLogger().
    *
    * @author <a href="mailto:[EMAIL PROTECTED]">Christian Haul</a>
  - * @version CVS $Revision: 1.1 $ $Date: 2001/11/19 16:28:33 $ */
  + * @version CVS $Revision: 1.2 $ $Date: 2001/11/23 10:50:36 $ */
   public abstract class AbstractAttributeHelper extends AbstractLoggable
       implements AttributeHelper, Configurable, Disposable { 
   
  
  
  
  1.2       +53 -16    
xml-cocoon2/scratchpad/src/org/apache/cocoon/acting/ModularDatabaseAccess/AttributeHelper.java
  
  Index: AttributeHelper.java
  ===================================================================
  RCS file: 
/home/cvs/xml-cocoon2/scratchpad/src/org/apache/cocoon/acting/ModularDatabaseAccess/AttributeHelper.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- AttributeHelper.java      2001/11/19 16:28:33     1.1
  +++ AttributeHelper.java      2001/11/23 10:50:36     1.2
  @@ -7,38 +7,75 @@
    
*****************************************************************************/
   package org.apache.cocoon.acting.ModularDatabaseAccess;
   
  +import java.util.SortedSet;
  +import java.util.Enumeration;
  +
   import org.apache.cocoon.environment.Request;
  +import org.apache.avalon.framework.component.Component;
   import org.apache.avalon.framework.configuration.Configuration;
   import org.apache.avalon.framework.configuration.ConfigurationException;
   
   /**
    * AttributeHelper specifies an interface for components that provide
  - * access to individual parameters e.g. request parameters, request
  + * access to individual attributes e.g. request parameters, request
    * attributes, session attributes &c.
    *
    * @author <a href="mailto:[EMAIL PROTECTED]">Christian Haul</a>
  - * @version CVS $Id: AttributeHelper.java,v 1.1 2001/11/19 16:28:33 haul Exp 
$
  + * @version CVS $Id: AttributeHelper.java,v 1.2 2001/11/23 10:50:36 haul Exp 
$
    * */
  -public interface AttributeHelper extends AccessHelper {
  +public interface AttributeHelper 
  +    extends Component 
  +{
       String ROLE = 
"org.apache.cocoon.acting.ModularDatabaseAccess.AttributeHelper";
  -    
  +
  +    /** 
  +     * Standard access to an attribute's value. If more than one value
  +     * exists, the first is returned. If the value does not exist,
  +     * null is returned. To get all values, use [EMAIL PROTECTED]
  +     * getAttributeValues} or [EMAIL PROTECTED] getAttributeSet} and [EMAIL 
PROTECTED]
  +     * getValue} to get them one by one.
  +     * @param name a String that specifies what the caller thinks
  +     * would identify an attribute. This is mainly a fallback if no
  +     * modeConf is present.
  +     * @param modeConf column's mode configuration from resource
  +     * description. This argument is optional.
  +     * @param request the request object
  +     */
  +    public Object getAttribute( String name, 
  +                             Configuration modeConf, 
  +                             Request request
  +                             )
  +     throws ConfigurationException;
  +
  +    /**
  +     * Returns an Enumeration of String objects containing the names
  +     * of the attributes available. If no attributes are available,
  +     * the method returns an empty Enumeration.
  +     * @param modeConf column's mode configuration from resource
  +     * description. This argument is optional.
  +     * @param request the request object
  +     */
  +    public Enumeration getAttributeNames( Configuration modeConf, 
  +                                       Request request
  +                                       )
  +     throws ConfigurationException;
  +
       /**
  -     * Return an object that is to be taken for insertion.
  +     * Returns an array of String objects containing all of the values
  +     * the given attribute has, or null if the attribute does not
  +     * exist. As an alternative, [EMAIL PROTECTED] getAttributeSet} together 
with
  +     * [EMAIL PROTECTED] getValue} can be used to get the values one by one.
        * @param name a String that specifies what the caller thinks
  -     * would identify a set of parameters. This is mainly a fallback
  +     * would identify an attributes. This is mainly a fallback
        * if no modeConf is present.
        * @param modeConf column's mode configuration from resource
  -     * description.  
  +     * description. This argument is optional.
        * @param request the request object
  -     * @param index Element from the getParameterSet() to identify an
  -     * instance in a set of similar parameters, when multiple rows are
  -     * inserted.
  -     * */
  -    public Object getValue( String name,
  -                         Configuration modeConf,
  -                         Request request, 
  -                         Object index
  -                         )
  +     */
  +    public Object[] getAttributeValues( String name, 
  +                                     Configuration modeConf, 
  +                                     Request request
  +                                     )
        throws ConfigurationException;
   
   }
  
  
  
  1.2       +16 -19    
xml-cocoon2/scratchpad/src/org/apache/cocoon/acting/ModularDatabaseAccess/HsqlIdentityKeyAttributeHelper.java
  
  Index: HsqlIdentityKeyAttributeHelper.java
  ===================================================================
  RCS file: 
/home/cvs/xml-cocoon2/scratchpad/src/org/apache/cocoon/acting/ModularDatabaseAccess/HsqlIdentityKeyAttributeHelper.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- HsqlIdentityKeyAttributeHelper.java       2001/11/19 16:28:33     1.1
  +++ HsqlIdentityKeyAttributeHelper.java       2001/11/23 10:50:36     1.2
  @@ -7,7 +7,7 @@
    
*****************************************************************************/
   package org.apache.cocoon.acting.ModularDatabaseAccess;
   
  -import java.lang.Long;
  +import java.lang.Integer;
   import java.util.SortedSet;
   import java.sql.CallableStatement;
   import java.sql.PreparedStatement;
  @@ -28,10 +28,10 @@
    * [EMAIL PROTECTED] http://hsqldb.sourceforge.net}
    *
    * @author <a href="mailto:[EMAIL PROTECTED]">Christian Haul</a>
  - * @version CVS $Id: HsqlIdentityKeyAttributeHelper.java,v 1.1 2001/11/19 
16:28:33 haul Exp $
  + * @version CVS $Id: HsqlIdentityKeyAttributeHelper.java,v 1.2 2001/11/23 
10:50:36 haul Exp $
    */
   public class HsqlIdentityKeyAttributeHelper 
  -    implements KeyAttributeHelper, ThreadSafe
  +    implements AutoIncrementHelper, ThreadSafe
   {
       
       public Object getPostValue( Configuration tableConf, 
  @@ -40,9 +40,11 @@
                                Connection conn, 
                                Statement stmt, 
                                Request request
  -                             ) throws SQLException, ConfigurationException 
  +                             ) 
  +     throws SQLException, 
  +            ConfigurationException 
       {
  -     Long id = null;
  +     Integer id = null;
        /*
        CallableStatement callStmt = conn.prepareCall("? = {CALL IDENTITY()}");
        callStmt.registerOutParameter(1, Types.INTEGER);
  @@ -53,7 +55,7 @@
        PreparedStatement pstmt = conn.prepareStatement("CALL IDENTITY()");
        ResultSet resultSet = pstmt.executeQuery();
        while ( resultSet.next() ) {
  -         id = new Long(resultSet.getInt(1));
  +         id = new Integer(resultSet.getInt(1));
        }
        resultSet.close();
   
  @@ -71,25 +73,20 @@
                               Configuration columnConf, 
                               Configuration modeConf, 
                               Connection conn, 
  -                            Request request,
  -                            Object idx
  -                            ) throws SQLException, ConfigurationException {
  +                            Request request
  +                            ) 
  +     throws SQLException,
  +            ConfigurationException 
  +    {
        return null;
       };
   
       public String getSubquery( Configuration tableConf, 
                               Configuration columnConf, 
                               Configuration modeConf 
  -                            ) throws ConfigurationException {
  -     return null;
  -    };
  -
  -    public SortedSet getAttributeSet( String name,
  -                                   Configuration modeConf,
  -                                   Request request
  -                                  )
  -     throws ConfigurationException
  +                            ) 
  +     throws ConfigurationException 
       {
        return null;
  -    }
  +    };
   }
  
  
  
  1.2       +14 -17    
xml-cocoon2/scratchpad/src/org/apache/cocoon/acting/ModularDatabaseAccess/IfxSerialKeyAttributeHelper.java
  
  Index: IfxSerialKeyAttributeHelper.java
  ===================================================================
  RCS file: 
/home/cvs/xml-cocoon2/scratchpad/src/org/apache/cocoon/acting/ModularDatabaseAccess/IfxSerialKeyAttributeHelper.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- IfxSerialKeyAttributeHelper.java  2001/11/19 16:28:33     1.1
  +++ IfxSerialKeyAttributeHelper.java  2001/11/23 10:50:36     1.2
  @@ -7,7 +7,7 @@
    
*****************************************************************************/
   package org.apache.cocoon.acting.ModularDatabaseAccess;
   
  -import java.lang.Long;
  +import java.lang.Integer;
   import java.util.SortedSet;
   import java.sql.Connection;
   import java.sql.Statement;
  @@ -25,10 +25,10 @@
    * (need another one for SERIAL8 ones!)
    *
    * @author <a href="mailto:[EMAIL PROTECTED]">Christian Haul</a>
  - * @version CVS $Id: IfxSerialKeyAttributeHelper.java,v 1.1 2001/11/19 
16:28:33 haul Exp $
  + * @version CVS $Id: IfxSerialKeyAttributeHelper.java,v 1.2 2001/11/23 
10:50:36 haul Exp $
    */
   public class IfxSerialKeyAttributeHelper 
  -    implements KeyAttributeHelper, ThreadSafe
  +    implements AutoIncrementHelper, ThreadSafe
   {
       
       public Object getPostValue( Configuration tableConf, 
  @@ -37,9 +37,11 @@
                                Connection conn, 
                                Statement stmt, 
                                Request request
  -                             ) throws SQLException, ConfigurationException 
  +                             ) 
  +     throws SQLException, 
  +            ConfigurationException 
       {
  -     return new Long(((com.informix.jdbc.IfxStatement) stmt).getSerial());
  +     return new Integer(((com.informix.jdbc.IfxStatement) stmt).getSerial());
       };
       
       public boolean includeInQuery() {
  @@ -53,25 +55,20 @@
                               Configuration columnConf, 
                               Configuration modeConf, 
                               Connection conn, 
  -                            Request request,
  -                            Object idx
  -                            ) throws SQLException, ConfigurationException {
  +                            Request request
  +                            ) 
  +     throws SQLException, 
  +            ConfigurationException
  +    {
        return null;
       };
   
       public String getSubquery( Configuration tableConf, 
                               Configuration columnConf, 
                               Configuration modeConf 
  -                            ) throws ConfigurationException {
  -     return null;
  -    };
  -
  -    public SortedSet getAttributeSet( String name,
  -                                   Configuration modeConf,
  -                                   Request request
  -                                  )
  +                            ) 
        throws ConfigurationException
       {
        return null;
  -    }
  +    };
   }
  
  
  
  1.2       +27 -37    
xml-cocoon2/scratchpad/src/org/apache/cocoon/acting/ModularDatabaseAccess/ManualKeyAttributeHelper.java
  
  Index: ManualKeyAttributeHelper.java
  ===================================================================
  RCS file: 
/home/cvs/xml-cocoon2/scratchpad/src/org/apache/cocoon/acting/ModularDatabaseAccess/ManualKeyAttributeHelper.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ManualKeyAttributeHelper.java     2001/11/19 16:28:33     1.1
  +++ ManualKeyAttributeHelper.java     2001/11/23 10:50:36     1.2
  @@ -16,7 +16,7 @@
   import org.apache.avalon.framework.configuration.Configuration;
   import org.apache.avalon.framework.configuration.ConfigurationException;
   import org.apache.avalon.framework.thread.ThreadSafe;
  -import java.lang.Long;
  +import java.lang.Integer;
   import java.util.Map;
   import java.util.HashMap;
   import java.util.SortedSet;
  @@ -34,42 +34,43 @@
    * requires only shared locks. C.f. "Phantom Problem"
    *
    * @author <a href="mailto:[EMAIL PROTECTED]">Christian Haul</a>
  - * @version CVS $Id: ManualKeyAttributeHelper.java,v 1.1 2001/11/19 16:28:33 
haul Exp $
  + * @version CVS $Id: ManualKeyAttributeHelper.java,v 1.2 2001/11/23 10:50:36 
haul Exp $
    */
   public class ManualKeyAttributeHelper 
  -    extends AbstractKeyAttributeHelper 
  +    extends AbstractAutoIncrementHelper 
       implements ThreadSafe
   {
       private Map selectStatements = new HashMap();
       
  -    public Object getPostValue ( Configuration tableConf, 
  -                              Configuration columnConf,
  -                              Configuration modenConf,
  -                              Connection conn, 
  -                              Statement stmt, 
  -                              Request request
  -                              ) 
  -     throws SQLException, ConfigurationException 
  +    public Object getPostValue( Configuration tableConf, 
  +                             Configuration columnConf,
  +                             Configuration modenConf,
  +                             Connection conn, 
  +                             Statement stmt, 
  +                             Request request
  +                             ) 
  +     throws SQLException, 
  +            ConfigurationException 
       {
        return null;
       };
       
  -    public boolean includeInQuery ( ) {
  +    public boolean includeInQuery( ) {
        return true;
       };
       
  -    public boolean includeAsValue ( ) {
  +    public boolean includeAsValue( ) {
        return true;
       };
   
  -    public Object getPreValue ( Configuration tableConf, 
  -                             Configuration columnConf,
  -                             Configuration modeConf,
  -                             Connection conn, 
  -                             Request request,
  -                             Object idx
  -                             ) 
  -     throws SQLException, ConfigurationException 
  +    public Object getPreValue( Configuration tableConf, 
  +                            Configuration columnConf,
  +                            Configuration modeConf,
  +                            Connection conn, 
  +                            Request request
  +                            ) 
  +     throws SQLException, 
  +            ConfigurationException 
       {
           /** Set the key value using SELECT MAX(keyname)+1 **/
        String tableName = tableConf.getAttribute("name","");
  @@ -81,28 +82,17 @@
           set.close();
           select_statement.close();
        getLogger().debug("autoincrementValue " + (maxid+1));
  -        return new Long(maxid + 1);
  +        return new Integer(maxid + 1);
       };
   
  -    public String getSubquery ( Configuration tableConf,
  -                             Configuration columnConf,
  -                             Configuration modeConf 
  -                             ) 
  +    public String getSubquery( Configuration tableConf,
  +                            Configuration columnConf,
  +                            Configuration modeConf 
  +                            ) 
        throws ConfigurationException 
       {
        return null;
       };
  -
  -
  -    public SortedSet getAttributeSet( String name,
  -                                   Configuration modeConf,
  -                                   Request request
  -                                  )
  -     throws ConfigurationException
  -    {
  -     return null;
  -    }
  -
   
       /**
        * Set the String representation of the MaxID lookup statement.  This is
  
  
  
  1.2       +14 -5     
xml-cocoon2/scratchpad/src/org/apache/cocoon/acting/ModularDatabaseAccess/OutputHelper.java
  
  Index: OutputHelper.java
  ===================================================================
  RCS file: 
/home/cvs/xml-cocoon2/scratchpad/src/org/apache/cocoon/acting/ModularDatabaseAccess/OutputHelper.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- OutputHelper.java 2001/11/19 16:28:33     1.1
  +++ OutputHelper.java 2001/11/23 10:50:36     1.2
  @@ -9,6 +9,7 @@
   
   import org.apache.cocoon.environment.Request;
   import org.apache.avalon.framework.component.Component;
  +import org.apache.avalon.framework.configuration.Configuration;
   
   /**
    * Communicate results to other components. This could be done via
  @@ -18,7 +19,7 @@
    * the transaction completes successfully.
    *
    * @author <a href="mailto:[EMAIL PROTECTED]">Christian Haul</a>
  - * @version CVS $Id: OutputHelper.java,v 1.1 2001/11/19 16:28:33 haul Exp $
  + * @version CVS $Id: OutputHelper.java,v 1.2 2001/11/23 10:50:36 haul Exp $
    * */
   public interface OutputHelper extends Component {
       String ROLE = 
"org.apache.cocoon.acting.ModularDatabaseAccess.OutputHelper";
  @@ -26,13 +27,16 @@
       
       /**
        * communicate an attribute value to further processing logic. 
  +     * @param modeConf column's mode configuration from resource
  +     * description. This argument is optional.
        * @param request The request object
        * @param name The attribute's label, consisting of "table.column"
        * or "table.column[index]" in case of multiple attributes of the
        * same spec.
        * @param value The attriute's value.
        * */
  -    public void setAttribute( Request request,
  +    public void setAttribute( Configuration modeConf,
  +                           Request request,
                              String name,
                              Object value
                              );
  @@ -41,13 +45,18 @@
       /**
        * retrieve an attribute from other processing steps. <em>Do we
        * really need this thingy?</em>
  +     * @param modeConf column's mode configuration from resource
  +     * description. This argument is optional.
        * @param request The request object
        * @param name The attribute's label, consisting of "table.column"
        * or "table.column[index]" in case of multiple attributes of the
        * same spec.
        * @return requested object.
  +     *
  +     * Really necessary?
        * */
  -    public Object getAttribute( Request request,
  +    public Object getAttribute( Configuration modeConf,
  +                             Request request,
                                String name );
   
       /**
  @@ -59,13 +68,13 @@
        * your data straight to some beans or other entities could result
        * in data corruption!</em>
        * */
  -    public void rollback( Request request, Exception e );
  +    public void rollback( Configuration modeConf, Request request, Exception 
e );
   
   
       /**
        * Signal that the database transaction completed
        * successfully. See notes on @link{rollback}.
        * */
  -    public void commit( Request request );
  +    public void commit( Configuration modeConf, Request request );
   
   }
  
  
  
  1.2       +65 -102   
xml-cocoon2/scratchpad/src/org/apache/cocoon/acting/ModularDatabaseAccess/RequestAttributeHelper.java
  
  Index: RequestAttributeHelper.java
  ===================================================================
  RCS file: 
/home/cvs/xml-cocoon2/scratchpad/src/org/apache/cocoon/acting/ModularDatabaseAccess/RequestAttributeHelper.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- RequestAttributeHelper.java       2001/11/19 16:28:33     1.1
  +++ RequestAttributeHelper.java       2001/11/23 10:50:36     1.2
  @@ -8,11 +8,8 @@
   package org.apache.cocoon.acting.ModularDatabaseAccess;
   
   import java.util.Enumeration;
  -import java.util.SortedSet;
  -import java.util.TreeSet;
  -import java.sql.Connection;
  -import java.sql.Statement;
  -import java.sql.SQLException;
  +import java.util.List;
  +import java.util.LinkedList;
   import org.apache.cocoon.environment.Request;
   import org.apache.avalon.framework.configuration.Configuration;
   import org.apache.avalon.framework.configuration.ConfigurationException;
  @@ -23,124 +20,90 @@
    * RequestAttributeHelper accesses request attributes.
    *
    * @author <a href="mailto:[EMAIL PROTECTED]">Christian Haul</a>
  - * @version CVS $Id: RequestAttributeHelper.java,v 1.1 2001/11/19 16:28:33 
haul Exp $
  + * @version CVS $Id: RequestAttributeHelper.java,v 1.2 2001/11/23 10:50:36 
haul Exp $
    */
   public class RequestAttributeHelper 
       extends AbstractAttributeHelper 
  -    implements KeyAttributeHelper, ThreadSafe
  +    implements ThreadSafe
   {
       
  -    // AccessHelper methods
  -
  -    /**
  -     * Return a sorted set of wildcard matches.
  -     * @param name String identifying the parameter
  -     * @param modeConf mode's configuration from resource description.
  -     * @param request the request object
  -     */
  -    public SortedSet getAttributeSet( String name,
  -                                   Configuration modeConf,
  -                                   Request request
  -                                   )
  -     throws ConfigurationException
  -    {
  -     // split the parameter's name so that the "*" could be determined
  -     // by looking at the parameters' names that start with the prefix
  -     // and end with the suffix
  -     String wildcard = name;
  -     if ( modeConf != null ) {
  -         wildcard = modeConf.getAttribute( "parameter", wildcard );
  -     }
  -     int wildcardIndex = wildcard.indexOf( "*" );
  -     String prefix = wildcard.substring( 0, wildcardIndex );
  -     String suffix;
  -     if ( wildcard.length() >= wildcardIndex + 1 ) {
  -         suffix = wildcard.substring( wildcardIndex + 1 );
  -     } else {
  -         suffix = "";
  -     }
  -     
  -     Enumeration names = request.getAttributeNames();
  -     SortedSet matchset = new TreeSet();
  -
  -     while (names.hasMoreElements()) {
  -         String pname = (String) names.nextElement();
  -         if ( pname.startsWith( prefix ) && pname.endsWith( suffix ) ) {
  -             String _wildcard = pname.substring( prefix.length() );
  -             _wildcard = _wildcard.substring( 0, _wildcard.length() - 
suffix.length() );
  -             matchset.add( _wildcard );
  -         }
  -     }
  -     return matchset;
  -    }
  -
  -    // AttributeHelper methods
  -
  -    public Object getValue( String name,
  -                         Configuration modeConf,
  -                         Request request, 
  -                         Object index
  -                         )
  +    public Object getAttribute( String name, 
  +                             Configuration modeConf, 
  +                             Request request
  +                             )
        throws ConfigurationException
       {
  -     int idx;
        String pname = name;
        if ( modeConf != null ) {
            pname = modeConf.getAttribute( "parameter", pname );
  -     }
  -     if ( index != null && ( idx = pname.indexOf( '*' ) ) != -1 ) {
  -         return request.getAttribute( pname.substring( 0, idx ) + index + 
pname.substring( idx + 1 ) );
  -     } else {
  -         return request.getAttribute( pname );
        }
  +     return request.getAttribute( pname );
       }
   
  -    
  -    // KeyAttributeHelper methods
  -    
   
  -    public Object getPostValue( Configuration tableConf, 
  -                             Configuration columnConf, 
  -                             Configuration modeConf, 
  -                             Connection conn, 
  -                             Statement stmt, 
  -                             Request request
  -                             ) 
  -     throws SQLException, ConfigurationException
  +    public Enumeration getAttributeNames( Configuration modeConf, 
  +                                       Request request
  +                                       )
  +     throws ConfigurationException
       {
  -     return null;
  +     return request.getAttributeNames();
       }
   
  -    public boolean includeInQuery() 
  +    public Object[] getAttributeValues( String name, 
  +                                     Configuration modeConf, 
  +                                     Request request
  +                                     )
  +     throws ConfigurationException
       {
  -     return true;
  -    }
  +     String wildcard = name;
  +     if ( modeConf != null ) {
  +         wildcard = modeConf.getAttribute( "parameter", wildcard );
  +     }
  +     int wildcardIndex = wildcard.indexOf( "*" );
  +     if ( wildcardIndex != -1 ) {
  +         // "*" contained in attribute name => combine all
  +         // attributes' values that match prefix, suffix
  +
  +         // split the attribute's name so that the "*" could be
  +         // determined by looking at the attributes' names that
  +         // start with the prefix and end with the suffix
  +         //
  +         String prefix = wildcard.substring( 0, wildcardIndex );
  +         String suffix;
  +         if ( wildcard.length() >= wildcardIndex + 1 ) {
  +             suffix = wildcard.substring( wildcardIndex + 1 );
  +         } else {
  +             suffix = "";
  +         }
  +         List values = new LinkedList();
  +         Enumeration names = request.getAttributeNames();
  +         
  +         while (names.hasMoreElements()) {
  +             String pname = (String) names.nextElement();
  +             if ( pname.startsWith( prefix ) && pname.endsWith( suffix ) ) {
  +                 values.add( request.getAttribute( pname ) );
  +             }
  +         }
   
  -    public boolean includeAsValue()
  -    {
  -     return true;
  -    }
  +         return values.toArray();
   
  -    public Object getPreValue( Configuration tableConf, 
  -                            Configuration columnConf, 
  -                            Configuration modeConf, 
  -                            Connection conn, 
  -                            Request request,
  -                            Object idx
  -                            ) 
  -     throws SQLException, ConfigurationException
  -    {
  -     return this.getValue( tableConf.getAttribute( "name" ) + "." + 
columnConf.getAttribute( "name" ), 
  -                           modeConf, request, idx );
  -    }
  +     } else {
  +         // no "*" in attribute name => just return all values of
  +         // this one attribute. Make sure, it's an array.
  +         
  +         Object value = request.getAttribute( wildcard );
  +         if ( value != null && !value.getClass().isArray() ) {
  +             Object[] values = new Object[1];
  +             values[0] = value;
  +             return values;
  +         } else {
  +             return (Object[]) value;
  +         }
   
  -    public String getSubquery( Configuration tableConf, 
  -                            Configuration columnConf, 
  -                            Configuration modeConf
  -                            ) 
  -     throws ConfigurationException
  -    {
  -     return null;
  +     }
  +     
       }
  +    
  +
   
   }
  
  
  
  1.2       +25 -11    
xml-cocoon2/scratchpad/src/org/apache/cocoon/acting/ModularDatabaseAccess/RequestAttributeOutputHelper.java
  
  Index: RequestAttributeOutputHelper.java
  ===================================================================
  RCS file: 
/home/cvs/xml-cocoon2/scratchpad/src/org/apache/cocoon/acting/ModularDatabaseAccess/RequestAttributeOutputHelper.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- RequestAttributeOutputHelper.java 2001/11/19 16:28:33     1.1
  +++ RequestAttributeOutputHelper.java 2001/11/23 10:50:36     1.2
  @@ -10,48 +10,60 @@
   import java.util.Enumeration;
   import org.apache.cocoon.environment.Request;
   import org.apache.avalon.framework.logger.AbstractLoggable;
  +import org.apache.avalon.framework.configuration.Configuration;
   
   /**
  - * Abstraction layer to encapsulate different DBMS behaviour for
  - * normal i.e. non key columns.
  + * Abstraction layer to encapsulate different output
  + * destinations. Configuration option &lt;key-prefix&gt; defaults to
  + * "org.apache.cocoon.acting.ModularDatabaseAccess.OutputHelper"+":"
    *
    * @author <a href="mailto:[EMAIL PROTECTED]">Christian Haul</a>
  - * @version CVS $Id: RequestAttributeOutputHelper.java,v 1.1 2001/11/19 
16:28:33 haul Exp $
  + * @version CVS $Id: RequestAttributeOutputHelper.java,v 1.2 2001/11/23 
10:50:36 haul Exp $
    * */
   public class RequestAttributeOutputHelper 
  -    extends AbstractLoggable
  +    extends AbstractOutputHelper
       implements OutputHelper {
       
       /**
        * communicate an attribute value to further processing logic. 
  +     * @param modeConf column's mode configuration from resource
  +     * description. This argument is optional.
        * @param request The request object
        * @param name The attribute's label, consisting of "table.column"
        * or "table.column[index]" in case of multiple attributes of the
        * same spec.
        * @param value The attriute's value.
        * */
  -    public void setAttribute( Request request,
  +    public void setAttribute( Configuration modeConf,
  +                           Request request,
                              String name,
                              Object value
                              )
       {
  -     
request.setAttribute("org.apache.cocoon.acting.ModularDatabaseAccess.OutputHelper:"+name,value);
  +     request.setAttribute( ( (String) this.settings.get("key-prefix",
  +                                                        
"org.apache.cocoon.acting.ModularDatabaseAccess.OutputHelper" ) )
  +                           + ":" + name, value);
       }
   
   
       /**
        * retrieve an attribute from other processing steps. <em>Do we
        * really need this thingy?</em>
  +     * @param modeConf column's mode configuration from resource
  +     * description. This argument is optional.
        * @param request The request object
        * @param name The attribute's label, consisting of "table.column"
        * or "table.column[index]" in case of multiple attributes of the
        * same spec.
        * @return requested object.
        * */
  -    public Object getAttribute( Request request,
  +    public Object getAttribute( Configuration modeConf,
  +                             Request request,
                                String name )
       {
  -     return 
request.getAttribute("org.apache.cocoon.acting.ModularDatabaseAccess.OutputHelper:"+name);
  +     return request.getAttribute( ( (String) this.settings.get("key-prefix",
  +                                                               
"org.apache.cocoon.acting.ModularDatabaseAccess.OutputHelper" ) )
  +                           + ":" + name );
       }
   
       /**
  @@ -63,7 +75,7 @@
        * your data straight to some beans or other entities could result
        * in data corruption!</em>
        * */
  -    public void rollback( Request request, Exception e )
  +    public void rollback( Configuration modeConf, Request request, Exception 
e )
       {
        /*
        Enumeration attributes = request.getAttributeNames();
  @@ -74,7 +86,9 @@
            }
        }
        */
  -     
request.setAttribute("org.apache.cocoon.acting.ModularDatabaseAccess.OutputHelper.Exception",e.getMessage());
  +     request.setAttribute( ( (String) this.settings.get("key-prefix",
  +                                                        
"org.apache.cocoon.acting.ModularDatabaseAccess.OutputHelper" ) ) + ":",
  +                           e.getMessage());
       };
   
   
  @@ -82,7 +96,7 @@
        * Signal that the database transaction completed
        * successfully. See notes on @link{rollback}.
        * */
  -    public void commit( Request request )
  +    public void commit( Configuration modeConf, Request request )
       {
        // empty method
       }
  
  
  
  1.2       +48 -120   
xml-cocoon2/scratchpad/src/org/apache/cocoon/acting/ModularDatabaseAccess/RequestParameterHelper.java
  
  Index: RequestParameterHelper.java
  ===================================================================
  RCS file: 
/home/cvs/xml-cocoon2/scratchpad/src/org/apache/cocoon/acting/ModularDatabaseAccess/RequestParameterHelper.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- RequestParameterHelper.java       2001/11/19 16:28:33     1.1
  +++ RequestParameterHelper.java       2001/11/23 10:50:36     1.2
  @@ -8,11 +8,8 @@
   package org.apache.cocoon.acting.ModularDatabaseAccess;
   
   import java.util.Enumeration;
  -import java.util.SortedSet;
  -import java.util.TreeSet;
  -import java.sql.Connection;
  -import java.sql.Statement;
  -import java.sql.SQLException;
  +import java.util.List;
  +import java.util.LinkedList;
   import org.apache.cocoon.environment.Request;
   import org.apache.avalon.framework.configuration.Configuration;
   import org.apache.avalon.framework.configuration.ConfigurationException;
  @@ -23,38 +20,53 @@
    * RequestParameterHelper accesses request parameters.
    *
    * @author <a href="mailto:[EMAIL PROTECTED]">Christian Haul</a>
  - * @version CVS $Id: RequestParameterHelper.java,v 1.1 2001/11/19 16:28:33 
haul Exp $
  + * @version CVS $Id: RequestParameterHelper.java,v 1.2 2001/11/23 10:50:36 
haul Exp $
    */
   public class RequestParameterHelper 
       extends AbstractAttributeHelper 
  -    implements KeyAttributeHelper, ThreadSafe
  +    implements ThreadSafe
   {
  -    
  -    // AccessHelper methods
  +    public Object getAttribute( String name, 
  +                             Configuration modeConf, 
  +                             Request request
  +                             )
  +     throws ConfigurationException
  +    {
  +     String pname = name;
  +     if ( modeConf != null ) {
  +         pname = modeConf.getAttribute( "parameter", pname );
  +     }
  +     return request.getParameter( pname );
  +    }
   
  -    /**
  -     * Return a sorted set of wildcard matches.
  -     * @param name String identifying the parameter
  -     * @param modeConf mode's configuration from resource description.
  -     * @param request the request object
  -     */
  -    public SortedSet getAttributeSet( String name,
  -                                   Configuration modeConf,
  -                                   Request request
  -                                   )
  +
  +    public Enumeration getAttributeNames( Configuration modeConf, 
  +                                       Request request
  +                                       )
        throws ConfigurationException
       {
  -     // split the parameter's name so that the "*" could be determined
  -     // by looking at the parameters' names that start with the prefix
  -     // and end with the suffix
  -     String wildcard = name;
  -     SortedSet matchset = new TreeSet();
  +     return request.getParameterNames();
  +    }
   
  +    public Object[] getAttributeValues( String name, 
  +                                     Configuration modeConf, 
  +                                     Request request
  +                                     )
  +     throws ConfigurationException
  +    {
  +     String wildcard = name;
        if ( modeConf != null ) {
  -         wildcard = modeConf.getAttribute( "parameter" );
  +         wildcard = modeConf.getAttribute( "parameter", wildcard );
        }
        int wildcardIndex = wildcard.indexOf( "*" );
        if ( wildcardIndex != -1 ) {
  +         // "*" contained in parameter name => combine all
  +         // parameters' values that match prefix, suffix
  +
  +         // split the parameter's name so that the "*" could be
  +         // determined by looking at the parameters' names that
  +         // start with the prefix and end with the suffix
  +         //
            String prefix = wildcard.substring( 0, wildcardIndex );
            String suffix;
            if ( wildcard.length() >= wildcardIndex + 1 ) {
  @@ -62,110 +74,26 @@
            } else {
                suffix = "";
            }
  -     
  +         List values = new LinkedList();
            Enumeration names = request.getParameterNames();
  -
  -         while ( names.hasMoreElements() ) {
  +         
  +         while (names.hasMoreElements()) {
                String pname = (String) names.nextElement();
                if ( pname.startsWith( prefix ) && pname.endsWith( suffix ) ) {
  -                 String _wildcard = pname.substring( prefix.length() );
  -                 _wildcard = _wildcard.substring( 0, _wildcard.length() - 
suffix.length() );
  -                 matchset.add( _wildcard );
  -             }
  -         }
  -     } else {
  -         // no wildcard, this might be an array, though
  -         Object[] parameterValues = request.getParameterValues( wildcard );
  -         if ( parameterValues != null ) {
  -             for ( int i = 0; i < parameterValues.length; i++ ) {
  -                 matchset.add( new Integer(i) );
  +                 values.add( request.getParameter( pname ) );
                }
            }
  -     }
  -
  -     return matchset;
  -    }
  -
  -    // AttributeHelper methods
   
  -    public Object getValue( String name,
  -                         Configuration modeConf,
  -                         Request request, 
  -                         Object index
  -                         )
  -     throws ConfigurationException
  -    {
  -     int idx;
  -     String pname = name;
  -     Object result = null;
  -     if ( modeConf != null ) {
  -         pname = modeConf.getAttribute( "parameter", pname );
  -     }
  +         return values.toArray();
   
  -     if (index != null && (idx = pname.indexOf('*')) != -1) {
  -         // index is wildcard match
  -         result = request.getParameter( pname.substring( 0, idx ) + index + 
pname.substring( idx + 1 ) );
        } else {
  -         if ( index != null ) {
  -             // index to array of multiple parameter values
  -             Object[] parameterValues = request.getParameterValues( pname );
  -             if ( parameterValues != null ) {
  -                 result = parameterValues[((Integer) index).intValue()];
  -             }
  -         } else {
  -             // no index present
  -             result = request.getParameter( pname );
  -         }
  +         // no "*" in parameter name => just return all values of
  +         // this one parameter.
  +         
  +         return request.getParameterValues( wildcard );
  +
        }
  -     return result;
  +     
       }
  -
  -    
  -    // KeyAttributeHelper methods
       
  -
  -    public Object getPostValue( Configuration tableConf, 
  -                             Configuration columnConf, 
  -                             Configuration modeConf, 
  -                             Connection conn, 
  -                             Statement stmt, 
  -                             Request request
  -                             ) 
  -     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, 
  -                            Request request,
  -                            Object idx
  -                            ) 
  -     throws SQLException, ConfigurationException
  -    {
  -     return this.getValue( tableConf.getAttribute("name") + "." + 
columnConf.getAttribute("name"),
  -                           modeConf, request, idx );
  -    }
  -
  -    public String getSubquery( Configuration tableConf, 
  -                            Configuration columnConf, 
  -                            Configuration modeConf
  -                            ) 
  -     throws ConfigurationException
  -    {
  -     return null;
  -    }
  -
   }
  
  
  
  1.1                  
xml-cocoon2/scratchpad/src/org/apache/cocoon/acting/ModularDatabaseAccess/AbstractAutoIncrementHelper.java
  
  Index: AbstractAutoIncrementHelper.java
  ===================================================================
  /*****************************************************************************
   * Copyright (C) The Apache Software Foundation. All rights reserved.        *
   * ------------------------------------------------------------------------- *
   * This software is published under the terms of the Apache Software License *
   * version 1.1, a copy of which has been included  with this distribution in *
   * the LICENSE file.                                                         *
   
*****************************************************************************/
  package org.apache.cocoon.acting.ModularDatabaseAccess;
  
  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.AbstractLoggable;
  
  import org.apache.cocoon.util.HashMap;
  
  /**
   * AbstractDatabaseHelper gives you the infrastructure for easily
   * deploying more AutoIncrementHelpers.  In order to get at the Logger, use
   * getLogger().
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Christian Haul</a>
   * @version CVS $Revision: 1.1 $ $Date: 2001/11/23 10:50:36 $ */
  public abstract class AbstractAutoIncrementHelper extends AbstractLoggable
      implements AutoIncrementHelper, Configurable, Disposable {
  
      /**
       * Stores (global) configuration parameters as <code>key</code> /
       * <code>value</code> pairs.
       */
      protected HashMap settings = null;
  
      /**
       * Configures the database access helper.
       *
       * 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 {
        getLogger().debug("ADBH: configure");
          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/scratchpad/src/org/apache/cocoon/acting/ModularDatabaseAccess/AbstractOutputHelper.java
  
  Index: AbstractOutputHelper.java
  ===================================================================
  /*****************************************************************************
   * Copyright (C) The Apache Software Foundation. All rights reserved.        *
   * ------------------------------------------------------------------------- *
   * This software is published under the terms of the Apache Software License *
   * version 1.1, a copy of which has been included  with this distribution in *
   * the LICENSE file.                                                         *
   
*****************************************************************************/
  package org.apache.cocoon.acting.ModularDatabaseAccess;
  
  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.AbstractLoggable;
  
  import org.apache.cocoon.util.HashMap;
  
  /**
   * AbstractOutputHelper gives you the infrastructure for easily
   * deploying more output helpers.  In order to get at the
   * Logger, use getLogger().
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Christian Haul</a>
   * @version CVS $Revision: 1.1 $ $Date: 2001/11/23 10:50:36 $ */
  public abstract class AbstractOutputHelper extends AbstractLoggable
      implements OutputHelper, Configurable, Disposable { 
  
      /**
       * Stores (global) configuration parameters as <code>key</code> /
       * <code>value</code> pairs.
       */
      protected HashMap settings = null;
  
      /**
       * Configures the database access helper.
       *
       * 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/scratchpad/src/org/apache/cocoon/acting/ModularDatabaseAccess/AutoIncrementHelper.java
  
  Index: AutoIncrementHelper.java
  ===================================================================
  /*****************************************************************************
   * Copyright (C) The Apache Software Foundation. All rights reserved.        *
   * ------------------------------------------------------------------------- *
   * This software is published under the terms of the Apache Software License *
   * version 1.1, a copy of which has been included  with this distribution in *
   * the LICENSE file.                                                         *
   
*****************************************************************************/
  package org.apache.cocoon.acting.ModularDatabaseAccess;
  
  import java.sql.Connection;
  import java.sql.Statement;
  import java.sql.SQLException;
  import org.apache.cocoon.environment.Request;
  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: AutoIncrementHelper.java,v 1.1 2001/11/23 10:50:36 haul 
Exp $ 
   * */
  public interface AutoIncrementHelper 
      extends Component 
  {
      String ROLE = 
"org.apache.cocoon.acting.ModularDatabaseAccess.AutoIncrementHelper";
      
      /**
       * 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.
       * */
      public Object getPostValue( Configuration tableConf, 
                                Configuration columnConf, 
                                Configuration modeConf, 
                                Connection conn, 
                                Statement stmt, 
                                Request request
                              ) 
        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.  
       * */
      public 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.
       * */
      public 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 
       * */
      public Object getPreValue( Configuration tableConf, 
                               Configuration columnConf, 
                               Configuration modeConf, 
                               Connection conn, 
                               Request request
                             ) 
        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.
       */
      public String getSubquery( Configuration tableConf, 
                               Configuration columnConf, 
                               Configuration modeConf
                               ) 
        throws ConfigurationException;
  
  }
  
  
  

----------------------------------------------------------------------
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