home *** CD-ROM | disk | FTP | other *** search
/ PC Professionell 2004 December / PCpro_2004_12.ISO / files / webserver / xampp / xampp-cocoon-addon-1.4.9-installer.exe / tutorial-develop-webapp.xml < prev    next >
Encoding:
Extensible Markup Language  |  2004-07-12  |  49.7 KB  |  1,137 lines

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!--
  3.   Copyright 1999-2004 The Apache Software Foundation
  4.  
  5.   Licensed under the Apache License, Version 2.0 (the "License");
  6.   you may not use this file except in compliance with the License.
  7.   You may obtain a copy of the License at
  8.  
  9.       http://www.apache.org/licenses/LICENSE-2.0
  10.  
  11.   Unless required by applicable law or agreed to in writing, software
  12.   distributed under the License is distributed on an "AS IS" BASIS,
  13.   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.   See the License for the specific language governing permissions and
  15.   limitations under the License.
  16. -->
  17. <!DOCTYPE document PUBLIC "-//APACHE//DTD Documentation V1.0//EN" "document-v10.dtd">
  18.  
  19. <document>
  20.  <header>
  21.   <title>How to develop Web Applications</title>
  22.   <authors>
  23.    <person name="Berin Loritsch" email="bloritsch@apache.org"/>
  24.    <person name="John Morrison" email="morrijr@apache.org"/>
  25.   </authors>
  26.  </header>
  27.  
  28.  <body>
  29.  
  30.  <s1 title="Introduction">
  31.   <p>Apache Cocoon is an XML publishing framework. It allows you to define XML
  32.      documents and transformations to be applied on it, to eventually
  33.      generate a presentation format of your choice (HTML, PDF, SVG, etc.).
  34.      Cocoon also gives you the possibility to have logic in your XML files
  35.      (so that the XML file itself can become dynamically generated).</p>
  36.   <p>Cocoon is developed on top of the Avalon Server Framework, which is a
  37.      stable and scalable framework.  You can find out more about Avalon in
  38.      this document: (ref: Avalon White Paper).  I highly suggest reading
  39.      this white paper as it covers many concepts that are key to Cocoon,
  40.      namely Separation of Concerns (SOC) and Inversion of Control (IoC).
  41.      It also covers foundational aspects of the Avalon Framework, so you
  42.      can have a better understanding on how Cocoon is structured.</p>
  43.   <p>Cocoon helps you separate out concern areas for web development.
  44.      The areas addressed are Logic, Content, Style, and Management.  There
  45.      are different mechanisms for each.</p>
  46.   <p>In order to learn how to use Cocoon, first make sure that you
  47.      <link href="../installing/index.html">install</link> it properly, then investigate
  48.      the many <link href="../overview.html#samples">samples</link>.
  49.      The following screenshots come from the
  50.      "<code>tutorial</code>" that is provided with Cocoon.
  51.      After you have built the demo webapp as per the installation
  52.      instructions (<code>build webapp</code>) then you can see this tutorial
  53.      in action via the Samples pages.</p>
  54.  
  55.   <s2 title="Separating Concerns">
  56.     <p>Cocoon is designed to allow Developers, Business Analysts,
  57.        Designers, and Administrators to work with each other without breaking
  58.        the other person's contribution.  The problem with using just JSPs, ASPs,
  59.        or ColdFusion templates is that all of the look, feel, and logic are
  60.        intertwined.  That means that maintenance is much more difficult, and the
  61.        project's true costs are delayed until the customer wants feature
  62.        enhancements or bugs fixed.  This also means that if the site design is
  63.        introduced late in the game, the cost of revamping the site becomes much
  64.        higher.</p>
  65.     <s3 title="Developers">
  66.       <p>Developer's jobs are to create the business logic and object model
  67.          behind the web application.  They are more concerned with functionality
  68.          than with layout or the words displayed on a screen.  These are the
  69.          people that will develop the Actions (Components that only process
  70.          information) and the hooks for how to get the necessary information
  71.          from business objects.</p>
  72.     </s3>
  73.     <s3 title="Business Analysts">
  74.       <p>The Business Analysts are the people who are concerned with the words
  75.          displayed on the screen, and to a certain extent, the layout.
  76.          Typically, they will be using the work done by the developer to put
  77.          together a generic markup that will be transformed into the results.
  78.          In small development environments, many times the developer takes on
  79.          both this role and the developer role.  Typically, the business analyst
  80.          will be working with the markup language that goes into the 
  81.          generator.</p>
  82.     </s3>
  83.     <s3 title="Designers">
  84.       <p>The designer is the person or group of people who are responsible to
  85.          provide the final look and feel of a site.  The designer does all the
  86.          graphics and HTML code.  In Cocoon, they will be working with the
  87.          Transformers that take an input and structure it in a final
  88.          presentation.</p>
  89.     </s3>
  90.     <s3 title="Administrators">
  91.       <p>The administrator is responsible for the sitemap which maps the URI
  92.          space to the different pipelines in Cocoon.  A pipeline is a path from
  93.          a Generator to a Serializer.  This means, that the administrator
  94.          decides that all requests for a resource with a ".html"
  95.          extension starts out as XML and ends up as HTML.  The Administrator
  96.          will work closely with the Designers and the Developers.  In the
  97.          absence of a dedicated administrator, one developer should assume that
  98.          role.  It is important that developers do not get bogged down in this
  99.          one Component.</p>
  100.     </s3>
  101.   </s2>
  102.   <s2 title="Development Style">
  103.     <p>You have to decide early on whether you will develop from a Business
  104.        Markup perspective, or develop from a Document Markup perspective.  They
  105.        have different ways of approaching the same problem.  Both approaches
  106.        have its tradeoffs.  In the end, you will find that you will need a
  107.        combination of different aspects of the two approaches.</p>
  108.     <s3 title="Business Markup Centric">
  109.       <p>This approach makes the Business Object the center of attention for
  110.          development.  This approach formalizes your business objects, and makes
  111.          sure that you always represent a business object in a standard manner. 
  112.          It's limitations come to bear when you have cases when you need
  113.          two different objects that need to be represented on the same logical
  114.          page.</p>
  115.     </s3>
  116.     <s3 title="Document Markup Centric">
  117.       <p>This approach feels the most natural to developers who come from
  118.          backgrounds with scripting languages.  This approach is a bit more
  119.          flexible in that you represent a page logically, with the wording as
  120.          the center of attention.  With this approach, it is up to the developer
  121.          to ensure that the business object is represented in a consistent
  122.          manner.</p>
  123.     </s3>
  124.     <s3 title="Hybrid Approach">
  125.       <p>We will develop a hybrid approach to development in this paper.  What
  126.          this means is that we start with a Document Markup Centric approach,
  127.          and add in support for specific Business Markup as it is needed.  In
  128.          the end, this is the most flexible and maintainable method for
  129.          development.</p>
  130.     </s3>
  131.   </s2>
  132.   <s2 title="The Concept">
  133.     <p>For the sake of this paper, we are going to develop a very simple
  134.        database-backed application that manages users and departments.  Each
  135.        element has a name and an identifier.  A department can have many
  136.        employees, but each employee can only have one department.  We will be
  137.        able to create, change, and delete both employees and departments.</p>
  138.     <s3 title="The SQL">
  139. <source><![CDATA[CREATE TABLE department {
  140.     department_id INT NOT NULL,
  141.     department_name VARCHAR (64) NOT NULL
  142. };
  143.  
  144. CREATE TABLE employee {
  145.     employee_id INT NOT NULL,
  146.     employee_name VARCHAR (64) NOT NULL,
  147.     department_id INT NOT NULL
  148. };
  149.  
  150. ALTER TABLE department ADD
  151.     PRIMARY KEY pkDepartment (department_id);
  152.  
  153. ALTER TABLE employee ADD
  154.     PRIMARY KEY pkEmployee (employee_id);
  155.  
  156. ALTER TABLE employee ADD
  157.     FOREIGN KEY department_id (department.department_id);]]></source>
  158.     </s3>
  159.     <s3 title="Facilities">
  160.       <ol>
  161.         <li>Create Department (need name only)</li>
  162.         <li>Update Department (change name, reassign potential employees to
  163.           department, create employee for department)</li>
  164.         <li>Delete Department</li>
  165.         <li>Find Department (by name, or by ID)</li>
  166.         <li>Create Employee (need name and department-create department if
  167.           needed)</li>
  168.         <li>Update Employee (change name, reassign department-create
  169.           department if needed)</li>
  170.         <li>Delete Employee</li>
  171.         <li>Find Employees (by name, by ID, or by Department)</li>
  172.       </ol>
  173.     </s3>
  174.     <s3 title="Layouts">
  175.      <p><link href="tutorial-shots.html">Various screenshots</link>
  176.       are available as a separate document, to portray the layout of
  177.       interfaces and results pages - apply your own style.</p>
  178.     </s3>
  179.   </s2>
  180.  </s1>
  181.  <s1 title="Diving In">
  182.   <p>In order to do anything in Cocoon, you will need a sitemap.  At this point
  183.      we will not go into detail but we will show you how to put an entry in so
  184.      you can see your stuff.  In most development situations, the sitemap will
  185.      be set up for you.  Since we want to start with a clean slate, take the
  186.      sitemap that comes with Cocoon's 
  187.      <link href="../overview.html#samples">samples</link>
  188.      and clear out everything under
  189.      the <code><map:pipelines></code> tag.  Next, you will add an entry
  190.      in the same location that looks like this:</p>
  191. <source>
  192.   <![CDATA[
  193. <map:pipeline>
  194.    <map:match pattern="">
  195.      <map:redirect-to uri="home.html"/>
  196.    </map:match>
  197.  
  198.    <map:match pattern="**.xml">
  199.      <map:generate src="docs/{1}.xml"/>
  200.      <map:serialize type="xml"/>
  201.    </map:match>
  202.  
  203.    <map:match pattern="**.html">
  204.      <map:generate src="docs/{1}.xml"/>
  205.      <map:transform src="stylesheets/apache.xsl"/>
  206.      <map:serialize/>
  207.    </map:match>
  208.  
  209.    <map:match pattern="images/**.gif">
  210.     <map:read src="resources/images/{1}.gif" mime-type="image/gif"/>
  211.    </map:match>
  212.  
  213.    <map:match pattern="images/**.jpg">
  214.     <map:read src="resources/images/{1}.jpg" mime-type="image/jpg"/>
  215.    </map:match>
  216.  
  217.    <map:match pattern="images/**.png">
  218.     <map:read src="resources/images/{1}.png" mime-type="image/png"/>
  219.    </map:match>
  220.  
  221.    <map:match pattern="resources/**.css">
  222.      <map:read src="resources/styles/{1}.css" mime-type="text/css"/>
  223.    </map:match>
  224.  
  225.    <map:match pattern="resources/**.js">
  226.      <map:read src="resource/styles/{1}.js"
  227.                mime-type="application/x-javascript"/>
  228.    </map:match>
  229.  
  230.   <map:handle-errors>
  231.     <map:transform src="stylesheets/system/error2html.xsl"/>
  232.     <map:serialize status-code="500"/>
  233.   </map:handle-errors>
  234. </map:pipeline>
  235.   ]]>
  236. </source>
  237.     <p>What this does is tell the sitemap that we want to capture all URLs
  238.        with a ".xml" extension, and find an equivalent file in the
  239.        "docs" subdirectory.  We are not performing any transformations
  240.        at this time.  The Sitemap is really a site administrator's job to
  241.        maintain.  There are some exceptions to this general rule, but we will
  242.        discuss them when needed.  We will use the Document Markup specified in
  243.        the StyleBook DTD format.</p>
  244.    <s2 title="Creating the Pages">
  245.     <p>Since we are only looking at XML right now, we need to make sure our
  246.        pages conform to the markup standards.  You will see how well this comes
  247.        in handy for debugging XSP (XML Server Pages) markup.  Since we already
  248.        have the Layout specified, and the database created, we will create our
  249.        markup.</p>
  250.     <p>Our home page is going to be really simple: a list of links that take us
  251.        to the main pages.</p>
  252. <source>
  253.   <![CDATA[
  254. <document>
  255.   <header>
  256.     <title>Home Page</title>
  257.   </header>
  258.   <body>
  259.     <s1 title="Welcome to Personnel Administrator">
  260.       <p>
  261.         Welcome to our Personnel Administrator.  You
  262.         can perform one of the following functions:
  263.       </p>
  264.       <ul>
  265.         <li>
  266.           <link href="search-dept.html">Search Departments</link>
  267.         </li>
  268.         <li>
  269.           <link href="search-empl.html">Search Employees</link>
  270.         </li>
  271.         <li>
  272.           <link href="create-dept.html">Create Departments</link>
  273.         </li>
  274.         <li>
  275.           <link href="edit-dept.html">Edit a Department</link>
  276.         </li>
  277.         <li>
  278.           <link href="create-empl.html">Create Employee</link>
  279.         </li>
  280.         <li>
  281.           <link href="edit-empl.html">Edit an Employee</link>
  282.         </li>
  283.       </ul>
  284.     </s1>
  285.   </body>
  286. </document>
  287.   ]]>
  288. </source>
  289.      <p>Even though this doesn't look like much right now, we have two
  290.         entries: "**.xml" and "**.html" for the same
  291.         resource.  Look at "home.html", and see how it looks now.
  292.         Quite a difference.  Don't remove the entry for viewing the page
  293.         as XML yet.  We need to use it to debug our XSP pages later.</p>
  294.      <s3 title="Our First Form">
  295.        <p>For now, we are going to skip the search functionality, and jump to
  296.           our "create" templates.  It is important to realize the
  297.           proper method of form handling.  While it is possible to create XSP
  298.           pages that perform the logic for you, this approach is not very
  299.           maintainable.  We also have to choose whether we will directly access
  300.           the database, or encapsulate that logic in objects.</p>
  301.        <p>The tradeoffs are that the direct SQL access is faster to get started,
  302.           but that it is harder to maintain in the end.  You may decide to start
  303.           with the direct SQL access at the beginning of a project, and build
  304.           the objects later.  With that in mind, we will use some functionality
  305.           that Cocoon has built in to make this approach a little easier.
  306.           Cocoon has a group of Database actions that allow you to map form
  307.           fields to dynamically created SQL calls.  It also has a logicsheet
  308.           that makes creating SQL bound pages a little easier.</p>
  309.        <p>Our first form is the "Create a Department" form.  The
  310.           website specification is missing the tags for form building, we will
  311.           provide an example here:</p>
  312. <source>
  313.   <![CDATA[
  314. <document>
  315.   <header>
  316.     <title>Department</title>
  317.   </header>
  318.   <body>
  319.     <s1 title="Create a Department">
  320.       <form handler="create-dept.html">
  321.         <p>
  322.           You can create a department by typing in the
  323.           name and pressing the "submit" button.
  324.         </p>
  325.         <p>
  326.           Name: <text name="name" size="30" required="true"/>
  327.         </p>
  328.         <submit name="Create Department"/>
  329.         <note>
  330.           * These fields are required.
  331.         </note>
  332.       </form>
  333.     </s1>
  334.   </body>
  335. </document> 
  336.   ]]>
  337. </source>
  338.        <p>It is important to note that the "submit" tag is transformed
  339.           into an HTML submit button with the name "cocoon-action-ACTIONNAME".
  340.           The "cocoon-action-ACTIONNAME" form parameter is a magic value that
  341.           Cocoon uses to select a specific action from a group of actions that
  342.           only gets executed during that time.  You will find that this page
  343.           displays correctly, but does not do anything yet.  The handler is
  344.           where the navigation goes once you click on the
  345.           "Create Department" button on the screen.  What we are going
  346.           to do is create one confirmation page for all the Department and
  347.           Employee pages.</p>
  348.        <p>Cocoon has a FormValidatorAction that will take care of ensuring the
  349.           input results are acceptable.  It also has the following database
  350.           actions for your convenience: DatabaseAddAction, DatabaseUpdateAction,
  351.           DatabaseDeleteAction, and DatabaseAuthenticatorAction.  We will only
  352.           need the Add, Update, and Delete actions for our simple webapp.  In
  353.           order to prepare them, we create an XML configuration file that tells
  354.           the actions how to map request parameters to database tables and place
  355.           constraints on the parameters.  For the Department form group, it will
  356.           look like this:</p>
  357. <source>
  358.   <![CDATA[
  359. <root>
  360.   <!-
  361.       The "parameter" elements identify the root constraints for
  362.       the FormValidatorAction.  We are specifying that the "id"
  363.       parameter is an integer (it limits to "long", "double",
  364.       "boolean", and "string").  We are specifying that the "name"
  365.       parameter is a string that is at least 5 characters--but no
  366.       more than 64 characters.
  367.   -->
  368.   <parameter name="id" type="long"/>
  369.   <parameter name="name" type="string" min-len="5" max-len="64"/>
  370.  
  371.   <!-
  372.       Each constraint set is used when we are defining a new way
  373.       of validating a form.  We define our constraint sets by
  374.       function.  Since we have the same basic form that is driving
  375.       the FormValidator, we have an update set and an add set.
  376.  
  377.       Note that you can impose additional constraints than the
  378.       default constraints listed above.  Also, you do not "have"
  379.       to enforce a constraint.  Each "validate" element below
  380.       identifies the parameter constraints we are enforcing.
  381.  
  382.       For more information view the JavaDocs for 
  383.       AbstractValidatorAction
  384.   -->
  385.   <constraint-set name="update">
  386.     <validate name="name"/>
  387.     <validate name="id" nullable="no" min="1"/>
  388.   </constraint-set>
  389.  
  390.   <constraint-set name="add">
  391.     <validate name="name"/>
  392.   </constraint-set>
  393.  
  394.   <!--
  395.        This is where we identify our table mappings so that the
  396.        Database Actions can work their magic.  Note that the
  397.        parameter names are the same as above--as well as the same
  398.        as form parameter names.
  399.  
  400.        First we tell the Database Actions that we are using the
  401.        "personnel" connection pool we set up in <code>cocoon.xconf</code>.
  402.        This file should be set up by the site administrator.
  403.  
  404.        We also tell the Database Actions the structure of the table
  405.        we will be populating.  The keys are used to identify which
  406.        columns will be treated as keys--they are treated different
  407.        when the different SQL statements are created.  Note that
  408.        there is a "mode" attribute in the key element.  The mode
  409.        refers to how new keys will be generated.  There are three
  410.        modes: "automatic" keys are generated by the database,
  411.        "manual" keys are generated by manually finding the largest
  412.        value and incrementing it, and finally "form" keys take the
  413.        key value from a parameter on the form.
  414.  
  415.        Both keys and values serve to map parameter names to table
  416.        columns, converting the value into the native type.  For a
  417.        list of supported types check out the JavaDocs for
  418.        AbstractDatabaseAction.
  419.   -->
  420.   <connection>personnel</connection>
  421.   <table name="department">
  422.     <keys>
  423.       <key param="id" dbcol="department_id" type="int" mode="manual"/>
  424.     </keys>
  425.     <values>
  426.       <value param="name" dbcol="department_name" type="string"/>
  427.     </values>
  428.   </table>
  429. </root>
  430.   ]]>
  431. </source>
  432.        <p>After you create the descriptor file, you will have to create some
  433.           entries in the Sitemap so you can take advantage of the form
  434.           descriptor.  First, the Sitemap has to be able to know how to
  435.           reference the Actions we want.  To do that, alter the
  436.           "map:actions" section to list all the actions we need:</p>
  437. <source>
  438.   <![CDATA[
  439. <map:actions>
  440.    <map:action name="dbAdd"
  441.                src="org.apache.cocoon.acting.DatabaseAddAction"/>
  442.    <map:action name="dbDel"
  443.                src="org.apache.cocoon.acting.DatabaseDeleteAction"/>
  444.    <map:action name="dbUpd"
  445.                src="org.apache.cocoon.acting.DatabaseUpdateAction"/>
  446.    <map:action name="form"
  447.                src="org.apache.cocoon.acting.FormValidatorAction"/>
  448. </map:actions>
  449.   ]]>
  450. </source>
  451.        <p>Lastly, we want to create an action set.  An action set is a group of
  452.           actions that will be applied at once.  If the action set entry has an
  453.           "action" parameter, then the specific action is only
  454.           executed when the ACTIONNAME of the magic "cocoon-action-ACTIONNAME"
  455.           request parameter matches the value of the "action" parameter.  For our
  456.           purposes, the action set we are defining is listed below (defined in
  457.           the sitemap):</p>
  458. <source>
  459.   <![CDATA[
  460. <map:action-sets>
  461.   <map:action-set name="process">
  462.    <map:act type="form" action="Create Department">
  463.      <map:parameter name="constraint-set" value="add"/>
  464.      <map:act type="dbAdd"/>
  465.    </map:act>
  466.    <map:act type="form" action="Update Department">
  467.      <map:parameter name="constraint-set" value="update"/>
  468.      <map:act type="dbUpd"/>
  469.    </map:act>
  470.    <map:act type="dbDel" action="Delete Department"/>
  471.   </map:action-set>
  472. </map:action-sets>
  473.   ]]>
  474. </source>
  475.        <p>Now that we have defined the actions we want, with the parameters that
  476.           control them during run-time, we can use it in our pipeline.</p>
  477. <source>
  478.   <![CDATA[
  479. <map:match pattern="*-dept.html">
  480.   <map:act set="process">
  481.     <map:parameter name="descriptor"
  482.                    value="context://docs/department-form.xml"/>
  483.     <map:parameter name="form-descriptor"
  484.                    value="context://docs/department-form.xml"/>
  485.     <map:generate type="serverpages" src="docs/confirm-dept.xsp"/>
  486.     <map:transform src="stylesheets/apache.xsl"/>
  487.     <map:serialize/>
  488.   </map:act>
  489.   <map:generate type="serverpages" src="docs/{1}-dept.xsp"/>
  490.   <map:transform src="stylesheets/apache.xsl"/>
  491.   <map:serialize/>
  492. </map:match>
  493.  
  494. <map:match pattern="*-dept.xml">
  495.   <map:act set="process">
  496.     <map:parameter name="descriptor"
  497.                    value="context://docs/department-form.xml"/>
  498.     <map:parameter name="form-descriptor"
  499.                    value="context://docs/department-form.xml"/>
  500.     <map:generate type="serverpages" src="docs/confirm-dept.xsp"/>
  501.     <map:serialize type="xml"/>
  502.   </map:act>
  503.   <map:generate type="serverpages" src="docs/{1}-dept.xsp"/>
  504.   <map:serialize type="xml"/>
  505. </map:match>
  506.   ]]>
  507. </source>
  508.        <p>This may not seem clear what is happening right now.  The way actions
  509.           work is if they return a null, nothing inside the "map:act"
  510.           entry will execute, and the request processing will flow through to
  511.           the second "map:generate" section.  This is a side affect of
  512.           using the FormValidatorAction.  If we choose to create our own
  513.           business objects and form validation framework, we are not constrained by
  514.           this construct.</p>
  515.        <p>In addition, we changed the type of generator we are using: we have
  516.           made it a "serverpages" (or XSP) generator.  We made the
  517.           transition now so that we can report information on what failed to the
  518.           user.  First, we need to convert our "create-dept.xml" file
  519.           to an XSP page so that we can see the page again (right now we will
  520.           get an error).  To do this, simply add a new tag to the base of the
  521.           document called "xsp:page" declaring the XSP namespace.  The
  522.           change will look like this:</p>
  523. <source>
  524.   <![CDATA[
  525. <xsp:page xmlns:xsp="http://apache.org/xsp">
  526.   <!-- The original document will be embedded here -->
  527. </xsp:page>
  528.   ]]>
  529. </source>
  530.        <p>To complete the transformation, we usually change the extension to
  531.           ".xsp" so we know what we are dealing with at a glance.
  532.           Create a new file called "confirm.xsp" with the following
  533.           contents:</p>
  534. <source>
  535.   <![CDATA[
  536. <xsp:page xmlns:xsp="http://apache.org/xsp">
  537. <document>
  538.   <header>
  539.     <title>Department</title>
  540.   </header>
  541.   <body>
  542.     <s1 title="Department Processed">
  543.       <p>
  544.         You have successfully processed the department.
  545.       </p>
  546.     </s1>
  547.   </body>
  548. </document>
  549. </xsp:page>
  550.   ]]>
  551. </source>          
  552.       <s4 title="Adding support for Error Reporting">
  553.         <p>In order to successfully report errors processing the page, add
  554.            another namespace declaration to the "xsp:page" element.
  555.            The final form page will look like this:</p>
  556. <source>
  557.   <![CDATA[
  558. <xsp:page xmlns:xsp="http://apache.org/xsp"
  559.           xmlns:xsp-formval="http://apache.org/xsp/form-validator/2.0">
  560. <document>
  561.   <header>
  562.     <title>Department</title>
  563.   </header>
  564.   <body>
  565.     <s1 title="Create a Department">
  566.       <form handler="create-dept.html">
  567.         <p>
  568.           You can create a department by typing in the
  569.           name and pressing the "submit" button.
  570.         </p>
  571.         <p>
  572.           Name: <text name="name" size="30" required="true"/><br />
  573.            <xsp:logic>
  574.              if (<xsp-formval:is-toosmall name="name"/>) {
  575.                  <xsp:text>"Name" must be at least 5 characters</xsp:text>
  576.              } else if (<xsp-formval:is-toolarge name="name"/>) {
  577.                  <xsp:text>"Name" was too long</xsp:text>
  578.              }
  579.            </xsp:logic>
  580.         </p>
  581.         <submit name="Create Department"/>
  582.         <note>
  583.           * These fields are required.
  584.         </note>
  585.       </form>
  586.     </s1>
  587.   </body>
  588. </document>
  589. </xsp:page>
  590.   ]]>
  591. </source>           
  592.       </s4>
  593.      </s3>
  594.      <s3 title="Adding Database Support with the ESQL Logicsheet">
  595.       <p>The "Create Employee" page is going to require database
  596.          access so that we know which Department a new employee is assigned to.
  597.          This is fairly easy to accomplish with the ESQL Logicsheet.  Again,
  598.          when you use the ESQL logicsheet, you lose some of your separation of
  599.          concerns.</p>
  600. <source>
  601.   <![CDATA[
  602. <xsp:page xmlns:xsp="http://apache.org/xsp"
  603.           xmlns:xsp-formval="http://apache.org/xsp/form-validator/2.0"
  604.           xmlns:esql="http://apache.org/cocoon/SQL/v2">
  605. <document>
  606.   <header>
  607.     <title>Employee</title>
  608.   </header>
  609.   <body>
  610.     <s1 title="Create an Employee">
  611.       <form handler="create-empl.html">
  612.         <p>
  613.           You can create a department by typing in the
  614.           name and pressing the "submit" button.
  615.         </p>
  616.         <p>
  617.           Name: <text name="name" size="30" required="true"/><br />
  618.            <xsp:logic>
  619.              if (<xsp-formval:is-null name="name"/>) {
  620.                  <xsp:text>"Name" cannot be empty</xsp:text>
  621.              } else if (<xsp-formval:is-toolarge name="name"/>) {
  622.                  <xsp:text>"Name" was too long</xsp:text>
  623.              }
  624.            </xsp:logic>
  625.         </p>
  626.         <p>
  627.           Department:
  628.           <select name="department">
  629.             <esql:connection>
  630.  
  631.               <!-- declare the connection pool we are using -->
  632.               <esql:pool>personnel</esql:pool>
  633.  
  634.               <!-- query execution blocks can be repeated -->
  635.               <esql:execute-query>
  636.  
  637.                 <!-- Find all departments and order them -->
  638.                 <esql:query>
  639.                   SELECT department_id, department_name
  640.                   FROM department ORDER BY department_name
  641.                 </esql:query>
  642.  
  643.                <!-- What to do with the results -->
  644.                 <esql:results>
  645.                   <!--
  646.                        A successful query that returns results
  647.                        executes this block.  You can also embed
  648.                        more "execute-query" blocks inside the
  649.                        row-results.  That way you can have queries
  650.                        that filter information based on the results
  651.                        of other queries.
  652.                   -->
  653.                   <esql:row-results>
  654.                     <option>
  655.                       <xsp:attribute name="name">
  656.                         <esql:get-string column="department_id"/>
  657.                       </xsp:attribute>
  658.                       <esql:get-string column="department_name"/>
  659.                     </option>
  660.                   </esql:row-results>
  661.                   <!--
  662.                        Other result types are "no-results" and
  663.                        "error-results".  A successful query that
  664.                        does not return results (an empty resultset)
  665.                        will use the XML embedded in the "no-results"
  666.                        section.  An unsuccessful query that throws
  667.                        an exception will use the XML embedded in
  668.                        the "error-results" section.
  669.                   -->
  670.                 </esql:results>
  671.               </esql:execute-query>
  672.             </esql:connection>
  673.           </select>
  674.         </p>
  675.         <submit name="Create Employee"/>
  676.         <note>
  677.           * These fields are required.
  678.         </note>
  679.       </form>
  680.     </s1>
  681.   </body>
  682. </document>
  683. </xsp:page>
  684.   ]]>
  685. </source>
  686.       <p>As you can see ESQL is flexible and powerful, but the cost of that
  687.          flexibility is a loss of readability.  Using a logicsheet to wrap
  688.          information in a business object is another alternative.  Notice how
  689.          ESQL works:</p>
  690.        <ul>
  691.         <li>First, we specify our connection information which will apply to
  692.               all queries in the ESQL structure.</li>
  693.         <li>Next, we specify our first query we are going to use.  Note that
  694.               you can nest queries as well as have more than one in an
  695.               "esql:connection" element.</li>
  696.         <li>Lastly, we specify how we process the results.  There are three
  697.               different types of results: "esql:row-results", 
  698.               "esql:no-results", and "esql:error-results".
  699.               This allows you to handle different scenarios easily.  It is
  700.               inside the individual results elements that we can nest new
  701.               queries to process.</li>
  702.        </ul>
  703.        <s4 title="A Note About Actions">
  704.         <p>Actions are the bread and butter of logic processing in Cocoon.
  705.            There are a number of approaches that you can take when developing
  706.            Actions.  You can create a specific action for each piece of
  707.            business logic.  This approach is very heavy handed and requires you
  708.            to spend a lot of development time creating actions.</p>
  709.         <p>The preferred method for creating actions is to provide a generic
  710.            action that can handle a wide range of specific actions.  The
  711.            Database Actions and Validator Actions are examples of this approach.
  712.            They will read a configuration file specified by a parameter, and
  713.            they will modify the specific results based on the configuration
  714.            file.  In order to take advantage of this for your own Actions, you
  715.            can extend the AbstractComplimentaryConfigurationAction.  Basically
  716.            what it does is encapsulate the logic for reading and caching the
  717.            Configuration information for your Action.</p>
  718.        </s4>
  719.      </s3>
  720.    </s2>
  721.    <s2 title="Redirects">
  722.       <p>Most web developers agree that redirecting a user based on input is a
  723.          valuable and necessary part of web development.  In Cocoon there are
  724.          only two locations where you can issue redirects: the Sitemap and
  725.          Actions.  In essence, Cocoon does require you to plan so that redirects
  726.          are only used when necessary.</p>
  727.       <p>One approach that is good to use is to require all traffic to go
  728.          through a URL controlling action.  The Action will test to see if the
  729.          user is logged in, and if not will send them to the login page.
  730.          Another derivation on this approach is to test for a user's role,
  731.          and if they do not have access redirect them to a different page.</p>
  732.    </s2>
  733.    <s2 title="Writing an Action">
  734.      <p>Writing an action is as simple as writing a Component that conforms to
  735.         the Action interface.  Be sure to examine the different Actions that are
  736.         in the org.apache.cocoon.acting package - you might find some abstract
  737.         actions that you can extend.  Actions are Avalon Components, so you may
  738.         want to read Avalon's Whitepaper for more information.</p>
  739.      <note>Actions will return a map that contains values that the sitemap
  740.            administrator can use in the sitemap.  If the Action returns a null,
  741.            then anything inside the "map:act" element will not be
  742.            executed.</note>
  743.      <s3 title="Return Values">
  744.       <p>The Action interface specifies that it returns a Map.  This Map is
  745.          used for value substitution in the sitemap, and communicating
  746.          information to other Actions.  When an Action is specified in the
  747.          sitemap, it uses the following syntax:</p>
  748. <source>
  749.   <![CDATA[
  750. <map:act type="my-action">
  751.   <map:generate src="{source}"/>
  752.   <map:transform src="doc2{theme}"/>
  753.   <map:serialize/>
  754. </map:act>
  755.   ]]>
  756. </source>
  757.       <p>The above code snippet assumes you have an Action with the name
  758.          "my-action" already specified.  It also assumes that there
  759.          are two "parameters" returned from the action in the Map. The
  760.          sitemap queries the returned Map for the "source" and
  761.          "theme" values, and substitutes their values in place of the
  762.          curly braces that referenced it.  In other words, when it sees the
  763.          "map:generate" with an src attribute of "{source}"
  764.          it looks in the Map.  For our discussion, let us say the value stored
  765.          is "index.xml".  The Sitemap will perform the substitution
  766.          so that the src attribute now containts "index.xml".</p>
  767.       <p>In the case that the above the action might return a null value.  In
  768.          that case, everything inside the "map:act" element is
  769.          skipped.  You can use this to good advantage like the *ValidatorActions
  770.          do.  If everything is validated correctly, they return a Map.  If there
  771.          is an error, they return a null, and place the information in Request
  772.          attributes.</p>
  773.      </s3>
  774.    </s2>
  775.  </s1>
  776.  <s1 title="Cocoon Supplied Components">
  777.   <p>Cocoon supplies a number of different Components for your use.  The types
  778.      of Components we will discuss here are Generators, Transformers,
  779.      Serializers, Readers, and Actions.  This are the important Components that
  780.      allow you to do you job.</p>
  781.   <s2 title="Generators">
  782.     <p>A Generator will create SAX events for a SAX stream-whether it reads from
  783.        an input stream or it generates it on the fly.  All built in generators
  784.        are in the package "org.apache.cocoon.generation".</p>
  785.     <s3 title="DirectoryGenerator">
  786.       <p>Reads a directory, and builds an XML document based on the contents.
  787.          You can pass parameters to it to control how it behaves (note
  788.          parameter names are case sensitive):</p>
  789.       <ul>
  790.         <li>dateFormat - a format string that you would use in the Java
  791.               SimpleDateFormat object</li>
  792.         <li>depth - the maximum number of directories deep the generator will
  793.               look (defaults to 1)</li>
  794.         <li>root - a regular expression to find the root directory</li>
  795.         <li>include - a regular expression to declare the files/directories
  796.               that will be included in the list</li>
  797.         <li>exclude - a regular expression to declare the files/directories
  798.               that will not be included in the list</li>
  799.       </ul>
  800.       <p>When you use this Generator, you must have the Jakarta Regexp package
  801.          installed in your WEB-INF/libs directory.  Also, the DirectoryGenerator
  802.          is not Cacheable so the results will be generated fresh each time.</p>
  803.       <p>The resulting XML looks like this:</p>
  804. <source>
  805.   <![CDATA[
  806. <?xml version="1.0"?>
  807.  
  808. <directory xmlns="http://apache.org/cocoon/directory/2.0"
  809.            name="C:\path\dir\"
  810.            lastModified="135432153351"
  811.            date="11 Jun 2001">
  812.   <file name="C:\path\dir\file.xml" lastModified="135432153351"
  813.         date="11 Jun 2001"/>
  814. </directory>
  815.   ]]>
  816. </source>
  817.     </s3>
  818.     <s3 title="FileGenerator">
  819.       <p>This generator and the ServerPagesGenerator will be your most used
  820.          generators.  The FileGenerator reads an XML file from an input source,
  821.          and converts it into a SAX stream.</p>
  822.       <p>When you use this Generator, you must have a JAXP 1.1 compliant parser
  823.          installed in your WEB-INF/libs directory.  You may also use the Xerces
  824.          parser bypassing the JAXP requirement.  The FileGenerator is Cacheable,
  825.          so the results will only be re-read when the file changes.</p>
  826.     </s3>
  827.     <s3 title="FragmentExtractorGenerator">
  828.       <p>This generator is used in conjunction with the
  829.          FragmentExtractorTransformer (more on that in the transformers
  830.          section).  The FragmentExtractorTransformer splits an XML document into
  831.          smaller parts so you can treat each smaller part as a unique document.
  832.          To see this in action, check out the Cocoon supplied 
  833.          <link href="../overview.html#samples">samples</link>
  834.          and click on the SVG Welcome page.</p>
  835.       <p>This Generator caches the results from the FragmentExtractorTransformer
  836.          for quick retrieval later.  It is Cacheable, so the fragments are
  837.          generated once and the cached version is read from that point
  838.          forward.</p>    
  839.     </s3>
  840.     <s3 title="HTMLGenerator">
  841.       <p>This generator is used to read in an HTML file that may not be properly
  842.          formatted to comply with XML standards.  The result is properly
  843.          formatted XHTML.</p>
  844.       <p>This generator requires the Tidy.jar file installed in the
  845.          WEB-INF/libs directory.  The HTMLGenerator is Cacheable, so the results
  846.          can be cached for application speedup.</p>      
  847.     </s3>
  848.     <s3 title="ImageDirectoryGenerator">
  849.       <p>This generator is an extension of the DirectoryGenerator, so it has the
  850.          same requirements.  It extends the markup to include two new attributes
  851.          for the "file" element: "height" and
  852.          "width".  The ImageDirectoryGenerator reads every GIF and
  853.          JPEG file to get the dimensions.</p>
  854.       <p>This generator is not Cacheable (just like the DirectoryGenerator).</p>
  855.     </s3>
  856.     <s3 title="JspGenerator">
  857.       <p>This generator executes a JSP file and parses the result.  The JSP must
  858.          generate valid XML, and be a file in the context.</p>
  859.       <p>This generator requires a JAXP 1.1 compliant parser or Xerces if your
  860.          environment will not allow you to install one.  It is also not
  861.          cacheable so the results are generated each time.</p>
  862.     </s3>
  863.     <s3 title="PhpGenerator">
  864.       <p>This generator functions just like the JspGenerator, but with PHP
  865.          templates.  The PHP must generate valid XML, and be a file in the
  866.          context.</p>
  867.       <p>This generator requires a JAXP 1.1 compliant parser and the
  868.          phpservlet.jar file that comes from http://php.net.  Install the files
  869.          in the WEB-INF/libs directory.  The PhpGenerator is not Cacheable.</p>
  870.     </s3>
  871.     <s3 title="RequestGenerator">
  872.       <p>This generator converts the Request object into an XML representation.
  873.          It is best used for debugging purposes.  The resulting XML follows:</p>
  874. <source>
  875.   <![CDATA[
  876. <request xmlns="http://apache.org/cocoon/request/2.0"
  877.          target="index.html" source="context://docs/index.xml">
  878.  
  879.   <requestHeaders>
  880.     <header name="HOST_NAME">johny-bravo.infoplanning.com</header>
  881.     <!-- repeat for each header -->
  882.   </requestHeaders>
  883.  
  884.   <requestParameters>
  885.     <parameter name="form-param">
  886.       <value>1</value>
  887.       <!-- repeat for each value in "form-param" -->
  888.     </parameter>
  889.     <!-- repeat for each parameter -->
  890.   </requestParameters>
  891.  
  892.   <configurationParameters>
  893.     <parameter
  894.        name="configurations">context://WEB-INF/cocoon.xconf</parameter>
  895.     <!-- repeat for each parameter -->
  896.   </configurationParameters>
  897. </request>
  898.   ]]>
  899. </source>
  900.       <p>The RequestGenerator does not have any special requirements for
  901.          libraries, and it is not Cacheable.</p>
  902.     </s3>
  903.     <s3 title="ScriptGenerator">
  904.       <p>The ScriptGenerator uses the Bean Scripting Framework (BSF) and an
  905.          associated interpreter to generate valid XML.  If you add language
  906.          support, you will have to embed the following configuration
  907.          information:</p>
  908. <source>
  909.   <![CDATA[
  910. <add-languages>
  911.   <!-- repeat the following for each language: -->
  912.   <language name="kawa-scheme"
  913.             src="org.gnu.kawa.bsf.engines.KawaEngine">
  914.     <extension>scm</extension>
  915.     <!-- repeat for each file extension -->
  916.   </language>
  917. </add-languages>
  918.   ]]>
  919. </source>
  920.       <p>The ScriptGenerator requires that you have the bsf.jar in your
  921.          WEB-INF/libs directory along with any jars for the script interpreters
  922.          you use.  The ScriptGenerator is not Cacheable.</p>
  923.     </s3>
  924.     <s3 title="ServerPagesGenerator">
  925.       <p>The ServerPagesGenerator is the XML Server Pages (XSP) engine.  It
  926.          automatically compiles a new Generator at runtime based on an input
  927.          XML file.</p>
  928.       <p>This generator requires that you have a JAXP 1.1 compliant parser and
  929.          XSLT engine installed in your WEB-INF/libs directory.  It also requires
  930.          you to have the JDK's tools.jar file in your classpath.  If you
  931.          reference any packages, they must also be in your classpath.  The
  932.          created generator is not Cacheable.</p>
  933.     </s3>
  934.     <s3 title="StatusGenerator">
  935.       <p>The StatusGenerator is another debug tool.  It provides status
  936.          information for the Cocoon engine.  The resultant XML is in the
  937.          following format:</p>
  938. <source>
  939.   <![CDATA[
  940. <statusinfo xmlns="http://apache.org/cocoon/status/2.0"
  941.             xmlns:xlink="http://www.w3.org/1999/xlink"
  942.             host="johnny-bravo.infoplanning.com"
  943.             date="7/16/2001 1:16:42 pm">
  944.   <group name="vm">
  945.     <group name="memmory">
  946.       <value name="total"><line>5213255</line></value>
  947.       <value name="free"><line>12321211</line></value>
  948.     </group>
  949.     <group name="jre">
  950.       <value name="version"><line>1.3.1</line></value>
  951.       <value name="java-vendor"
  952.              xlink:type="simple"
  953.              xlink:href="http://java.sun.com/jdk/1.3/">
  954.         <line>Sun Microsystems Inc.</line>
  955.       </value>
  956.     </group>
  957.     <group name="operating-system">
  958.       <value name="name"><line>Windows 2000</line></value>
  959.       <value name="architecture"><line>x86</line></value>
  960.       <value name="version"><line>5.0</line></value>
  961.     </group>
  962.   </group>
  963.   <value name="classpath">
  964.     <line>C:\tomcat\lib\tomcat.jar</line>
  965.     <line>C:\jdk1.3.1\lib\tools.jar</line>
  966.   </value>
  967. </statusinfo>
  968.   ]]>
  969. </source>
  970.       <p>The results are not cacheable, and do not require any special
  971.          libraries.</p>
  972.     </s3>
  973.     <s3 title="StreamGenerator">
  974.       <p>The StreamGenerator is used to convert the Request's InputStream
  975.          into a SAX XML stream.  Alternately, it will accept the magic form
  976.          parameter "form-name" and read the input stream that the
  977.          parameter points to.</p>
  978.       <p>This generator requires the JAXP 1.1 compliant parser (or Xerces).  It
  979.          is not cacheable.</p>
  980.     </s3>
  981.     <s3 title="VelocityGenerator">
  982.       <p>The VelocityGenerator is used to convert the output from the Velocity
  983.          template engine to a valid XML stream.</p>
  984.       <p>This generator requires Jakarta Velocity and a JAXP 1.1 compliant
  985.          parser installed in WEB-INF/libs.  It is not Cacheable.</p>
  986.     </s3>
  987.   </s2>
  988.   <s2 title="Transformers">
  989.     <p>Transformers read a SAX stream, manipulate the XML stream, and send the
  990.        results to the next Component in the chain.  All built in generators are
  991.        in the package "org.apache.cocoon.generation".</p>
  992.     <s3 title="CIncludeTransformer">
  993.       <p>The CIncludeTransformer looks for instances of the
  994.          "ci:include" element, and will embed another XML resource in
  995.          your document.  That resource can be in the sitemap so you can include
  996.          the results of processed XSP pages.  An example follows:</p>
  997. <source>
  998.   <![CDATA[
  999. <document xmlns:ci="http://apache.org/cocoon/include/1.0">
  1000.   <ci:include src="cocoon://my-resource.xml"
  1001.               element="body"
  1002.               ns="http://mycompany.com/my-resource/1.0"
  1003.               prefix="res"/>
  1004. </document>
  1005.   ]]>
  1006. </source>
  1007.       <p>The Transformer will read the results from the sitemap, and embed it
  1008.          into this document with a new root element "body" using a new
  1009.          namespace (xmlns:res="http://mycompany.com/my-resource/1.0").
  1010.          The results are not cached.</p>
  1011.     </s3>
  1012.     <s3 title="FilterTransformer">
  1013.       <p>The FilterTransformer will look for instances of an element you specify
  1014.          using parameters, and will not forward any SAX events for that element
  1015.          or any child elements.  You can pass parameters to it to control how it
  1016.          behaves (note parameter names are case sensitive):</p>
  1017.       <ul>
  1018.         <li>element-name - The name of the element to filter</li>
  1019.         <li>count - the number of times the element will be filtered</li>
  1020.         <li>blocknr - the element number that filtering begins</li>
  1021.       </ul>
  1022.     </s3>
  1023.     <s3 title="FragmentExtractorTransformer">
  1024.       <p>This is transformation half of the FragmentExtractor.  This transformer
  1025.          sieves an incoming stream of xml with embedded SVG images and replaces
  1026.          the images with a xlink locator pointing to the image.  Ultimately this
  1027.          could be much more general, but currently it is mainly an SVG
  1028.          extraction.</p>
  1029.     </s3>
  1030.     <s3 title="I18nTransformer">
  1031.       <p>This is Cocoon's port of Infozone Group's I18nProcessor.  The
  1032.          word i18n is a shorthand for the longer word
  1033.          "internationalization" (starts with 'i', ends with
  1034.          'n', and has 18 letters in the middle).  The
  1035.          internationalization transformer allows you to look up references by
  1036.          key in an XML dictionary.  This allows you to support your same
  1037.          business processes in many different countries.  You have to pass
  1038.          parameters to it so that it knows how to process i18n requests:</p>
  1039.       <ul>
  1040.         <li>default_lang - The default language if the requested language does
  1041.               not exist (two character country code)</li>
  1042.         <li>avalailable_lang_X - Language available by the dictionary (two
  1043.               character country code).  Replace the 'X' in the
  1044.               attribute with a number (1, 2, 3).</li>
  1045.         <li>src - The location of the dictionary file.</li>
  1046.       </ul>
  1047.       <p>The I18nTransformer reads the request parameter "lang" to
  1048.          determine which language to display to the user.  To translate text
  1049.          either embed the text inside the "i18n:text" element, or the
  1050.          attribute name inside the "i18n:attr" attribute.</p>
  1051. <source>
  1052.   <![CDATA[
  1053. <document xmlns:i18n="http://apache.org/cocoon/i18n/2.0">
  1054.   <body>
  1055.     <s1 title="Test Title" i18n:attr="title">
  1056.       <p>
  1057.        <i18n:text>This is replaceable text.</i18n:text>
  1058.       </p>
  1059.     </s1>
  1060.   </body>
  1061. </document>
  1062.   ]]>
  1063. </source>         
  1064.     </s3>
  1065.     <s3 title="LDAPTransformer">
  1066.       <p>The LDAPTransformer is a class that can be plugged into a pipeline to
  1067.          transform the SAX events which passes through this transformer into
  1068.          queries an responses to/from a LDAP interface.</p>
  1069.     </s3>
  1070.   </s2>
  1071.  </s1>
  1072.  <s1 title="The Sitemap">
  1073.   <p>This section is meant primarily as a reference for the Sitemap Manager.
  1074.      The person in this role needs to have a better understanding of the sitemap
  1075.      than any other role.  The sitemap is a relatively new concept, and as such
  1076.      is subject to refinement.  There have been a couple of proposals to replace
  1077.      it with something else, but nothing has been started yet.</p>
  1078.   <p>The Sitemap is composed of three major parts: component declaration,
  1079.      resource declaration, and pipeline declaration.  You will only use a few
  1080.      different types of components in the sitemap: Generators, Transformers,
  1081.      Serializers, Readers, Matchers, Selectors, and Actions.  Generators create
  1082.      XML and pass the results in a SAX stream.  Transformers read a SAX stream
  1083.      and manipulate the results on the way through.  Serializers read a SAX
  1084.      stream, and convert it into the servlet's output stream.  Readers read
  1085.      an input stream and copy the results to the servlet's output stream.  
  1086.      Matchers and Selectors are used to choose how to process an incoming
  1087.      request.  Lastly, Actions are used to perform logic only functions (no
  1088.      display logic).</p>
  1089.   <p>Below is the root element of all sitemaps:</p>
  1090. <source>
  1091.   <![CDATA[
  1092. <map:sitemap xmlns:map="http://apache.org/cocoon/sitemap/1.0">
  1093. </map:sitemap>
  1094.   ]]>
  1095. </source>
  1096.     <s2 title="Choosing your Components">
  1097.       <p>As previously discussed, you may choose a number of components to use
  1098.          in your own system.  This section identifies the different components
  1099.          you can use, and what they do.  Before we begin, I must state that
  1100.          every component is declared in the "map:components" element
  1101.          of the Sitemap:</p>
  1102. <source>
  1103.   <![CDATA[
  1104. <map:components>
  1105. </map:components>
  1106.   ]]>
  1107. </source>
  1108.       <s3 title="Generators">
  1109.         <p>All generators are declared within the "map:generators"
  1110.            element that is a child of the "map:components"
  1111.            element:</p>
  1112. <source>
  1113.   <![CDATA[
  1114. <map:generators>
  1115.   <map:generator name="file"
  1116.                  src="org.apache.cocoon.generation.FileGenerator"/>
  1117. </map:generators>
  1118.   ]]>
  1119. </source>           
  1120.         <p>Most Generators do not have configuration information, so the
  1121.            "map:generator" element is left empty.  If there were
  1122.            configuration information to pass to the generator, it would be
  1123.            placed inside the element.  As you can see in the sitemap snippet
  1124.            above, you declare a generator with the "map:generator"
  1125.            element, a "name" attribute, and a "src"
  1126.            attribute.  The "name" attribute is how you will refer to
  1127.            this specific type of generator from this point forward.  The
  1128.            "src" attribute is the fully qualified class name of the
  1129.            Generator class.  In fact this construct is the same for all
  1130.            component types - the only thing that changes is the elements that
  1131.            declare the type of Component we are dealing with.</p>
  1132.       </s3>
  1133.     </s2>         
  1134.  </s1>
  1135. </body>
  1136. </document>
  1137.