summaryrefslogtreecommitdiff
path: root/docs/users_guide_src/webware.tex
blob: a5702d82ad0c50dcd46c0d95bb039b292e5c579e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Using Cheetah with Webware}
\label{webware}

{\bf Webware for Python} is a 'Python-Powered Internet Platform' that runs
servlets in a manner similar to Java servlets.  {\bf WebKit} is the name of
Webware's application server.  For more details, please visit
\url{http://webware.sourceforge.net/}.

All comments below refer to the official version of Webware, the DamnSimple!
offshoot at ?, and the now-abandoned WebwareExperimental implementation at
\url{http://sourceforge.net/projects/expwebware/}, except where noted.  All the
implementations are 95\% identical to the servlet writer: their differences lie
in their internal structure and configuration files.  One difference is that
the executable you run to launch standard Webware is called \code{AppServer},
whereas in WebwareExperimental it's called \code{webkit}. But to servlets
they're both "WebKit, Webware's application server", so it's one half dozen to
the other.  In this document, we generally use the term {\bf WebKit} to refer
to the currently-running application server.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Installing Cheetah on a Webware system}
\label{webware.installing}

Install Cheetah after you have installed Webware, following the instructions in
chapter \ref{gettingStarted}.

The standard Cheetah test suite ('cheetah test') does not test Webware features.
We plan to build a test suite that can run as a Webware servlet, containing
Webware-specific tests, but that has not been built yet.  In the meantime, you
can make a simple template containing something like "This is a very small
template.", compile it, put the *.py template module in a servlet
directory, and see if Webware serves it up OK.  

{\em You must not have a Webware context called "Cheetah".}  If you do, Webware
will mistake that directory for the Cheetah module directory, and all 
template-servlets will bomb out with a "ImportError: no module named Template".
(This applies only to the standard Webware; WebwareExperimental does not have
contexts.)

If Webware complains that it cannot find your servlet, make sure
'.tmpl' is listed in 'ExtensionsToIgnore' in your 'Application.config' file.

% @@MO: Should explain extension cascading and how without it, standard
% Webware pretends a file doesn't exist if it finds two or more servable files
% that match the URL.



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Containment vs Inheritance}
\label{webware.background}

Because Cheetah's core is flexible, there are many ways to integrate it with
Webware servlets.  There are two broad strategies: the {\bf Inheritance
approach} and the {\bf Containment approach}.  The difference is
that in the Inheritance approach, your template object \code{\em is} the
servlet, whereas in the Containment approach, the servlet is not a template but
merely {\em uses} template(s) for portion(s) of its work.

The Inheritance approach is recommended for new sites because it's simpler, and
because it scales well for large sites with a
site->section->subsection->servlet hierarchy.  The Containment approach is
better for existing servlets that you don't want to restructure.  For instance,
you can use the Containment approach to embed a discussion-forum table at the
bottom of a web page.  

However, most people who use Cheetah extensively seem
to prefer the Inheritance approach because even the most analytical servlet
needs to produce {\em some} output, and it has to fit the site's look and feel
{\em anyway}, so you may as well use a template-servlet as the place to put the
output.  Especially since it's so easy to add a template-servlet to a site once
the framework is established.  So we recommend you at least evaluate the
effort that would be required to convert your site framework to template
superclasses as described below, vs the greater flexibility and manageability
it might give the site over the long term.  You don't necessarily have to
convert all your existing servlets right away: just build common site templates
that are visually and behaviorally compatible with your specification, and use
them for new servlets.  Existing servlets can be converted later, if at all.

Edmund Liam is preparing a section on a hybrid approach, in which the 
servlet is not a template, but still calls template(s) in an inheritance
chain to produce the output.  The advantage of this approach is that you
aren't dealing with \code{Template} methods and Webware methods in the
same object.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsubsection{The Containment Approach}
\label{webware.containment}

In the Containment approach, your servlet is not a template.  Instead, it 
it makes its own arrangements to create and use template object(s) for whatever
it needs.  The servlet must explicitly call the template objects'
\code{.respond()} (or \code{.\_\_str\_\_()}) method each time it needs to fill
the template.  This does not present the output to the user; it merely gives
the output to the servlet.  The servlet then calls its
\code{\#self.response().write()} method to send the output to the user.

The developer has several choices for managing her templates.  She can store the
template definition in a string, file or database and call
\code{Cheetah.Template.Template} manually on it.  Or she can put the
template definition in a *.tmpl file and use {\bf cheetah compile} (section
\ref{howWorks.cheetah-compile}) to convert it to a Python class in a *.py
module, and then import it into her servlet.

Because template objects are not thread safe, you should not store one
in a module variable and allow multiple servlets to fill it simultaneously.
Instead, each servlet should instantiate its own template object.  Template
{\em classes}, however, are thread safe, since they don't change once created.
So it's safe to store a template class in a module global variable.

% @@MO: Example of containment.


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsubsection{The Inheritance Approach}
\label{webware.inheritance}

In the Inheritance approach, your template object doubles as as Webware 
servlet, thus these are sometimes called {\bf template-servlets}.  {\bf cheetah
compile} (section \ref{howWorks.cheetah-compile}) automatically creates modules
containing valid Webware servlets.  A servlet is a subclass of Webware's
\code{WebKit.HTTPServlet} class, contained in a module with the same name as
the servlet.  WebKit uses the request URL to find the module, and then
instantiates the servlet/template.  The servlet must have a \code{.respond()}
method (or \code{.respondToGet()}, \code{.respondToPut()}, etc., but the
Cheetah default is \code{.respond()}).  Servlets created by \code{cheetah
compile} meet all these requirements.

(Cheetah has a Webware plugin that automatically converts a \code{.tmpl servlet
file} into a \code{.py servlet file} when the \code{.tmpl servlet file} is
requested by a browser.  However, that plugin is currently unavailable because
it's being redesigned.  For now, use \code{cheetah compile} instead.)

What about logic code?  Cheetah promises to keep content (the placeholder
values), graphic design (the template definition and is display logic), and
algorithmic logic (complex calculations and side effects) separate.  How?
Where do you do form processing?

The answer is that your template class can inherit from a pure Python class
containing the analytical logic.  You can either use the \code{\#extends}
directive in Cheetah to indicate the superclass(es), or write a Python
\code{class} statement to do the same thing.  See the template
\code{Cheetah.Templates.SkeletonPage.tmpl} and its pure Python class
\code{Cheetah.Templates.\_SkeletonPage.py} for an example of a template
inheriting logic code.  (See sections \ref{inheritanceEtc.extends} and
\ref{inheritanceEtc.implements} for more information about \code{\#extends} and
\code{\#implements}.  They have to be used a certain right way.)

If \code{\#WebKit.HTTPServlet} is not available, Cheetah fakes it with a
dummy class to satisfy the dependency.  This allows servlets to be tested on
the command line even on systems where Webware is not installed.  This works
only with servlets that don't call back into WebKit for information about the
current web transaction, since there is no web transaction.  Trying to access
form input, for instance, will raise an exception because it depends on a
live web request object, and in the dummy class the request object is
\code{None}.

Because Webware servlets must be valid Python modules, and ``cheetah compile''
can produce only valid module names, if you're converting an existing site that
has .html filenames with hyphens (-), extra dots (.), etc, you'll have to
rename them (and possibly use redirects).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Site frameworks}
\label{webware.siteFrameworks}

Web sites are normally arranged hierarchically, with certain features common 
to every page on the site, other features common to certain sections or
subsections, and others unique to each page.  You can model this easily with
a hierarchy of classes, with specific servlets inheriting from their more
general superclasses.  Again, you can do this two ways, using Cheetah's
{\bf Containment} approach or {\bf Inheritance} approach.

In the Inheritance approach, parents provide \code{\#block}s and children
override them using \code{\#def}.  Each child \code{\#extend}s its immediate
parent.  Only the leaf servlets need to be under WebKit's document root
directory.  The superclass servlets can live anywhere in the filesystem
that's in the Python path.  (You may want to modify your WebKit startup 
script to add that library directory to your \code{PYTHONPATH} before starting
WebKit.)

% @@MO Examples: simple, IronSite, SkeletonPage.

Section \ref{libraries.templates.skeletonPage} contains information on a stock
template that simplifies defining the basic HTML structure of your web
page templates.  

In the Containment approach, your hierarchy of servlets are not templates, but
each uses one or more templates as it wishes.  Children provide callback
methods to to produce the various portions of the page that are their
responsibility, and parents call those methods.  Webware's \code{WebKit.Page}
and \code{WebKit.SidebarPage} classes operate like this.

% @@MO Show examples of WebKit.Page and WebKit.SidebarPage.

Note that the two approaches are not compatible!  \code{WebKit.Page} was not
designed to intermix with \code{Cheetah.Templates.SkeletonPage}.  Choose either
one or the other, or expect to do some integration work.  

If you come up with a different strategy you think is worth noting in this
chapter, let us know.


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Directory structure}
\label{webware.directoryStructure}

Here's one way to organize your files for Webware+Cheetah.

\begin{verbatim}
www/                         # Web root directory.
    site1.example.com/       # Site subdirectory.
        apache/              # Web server document root (for non-servlets).
        www/                 # WebKit document root. 
           index.py          # http://site1.example.com/
           index.tmpl        # Source for above.
           servlet2.py       # http://site1.example.com/servlet2
           servlet2.tmpl     # Source for above.
        lib/                 # Directory for helper classes.
           Site.py           # Site superclass ("#extends Site").
           Site.tmpl         # Source for above.
           Logic.py          # Logic class inherited by some template.
        webkit.config        # Configuration file (for WebwareExperimental).
        Webware/             # Standard Webware's MakeAppWorkDir directory.
           AppServer         # Startup program (for standard Webware).
           Configs/          # Configuration directory (for standard Webware).
               Application.config
                             # Configuration file (for standard Webware). 
    site2.example.org/       # Another virtual host on this computer....
\end{verbatim}



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Initializing your template-servlet with Python code}
\label{webware.calculations}

If you need a place to initialize variables or do calculations for your
template-servlet, you can put it in an \code{.awake()} method because WebKit
automatically calls that early when processing the web transaction.  If you
do override \code{.awake()}, be sure to call the superclass \code{.awake}
method.  You probably want to do that first so that you have access to the
web transaction data \code{Servlet.awake} provides.  You don't have to worry
about whether your parent class has its own \code{.awake} method, just call
it anyway, and somebody up the inheritance chain will respond, or at minimum
\code{Servlet.awake} will respond.  Section
\ref{tips.callingSuperclassMethods} gives examples of how to call a
superclass method.

As an alternative, you can put all your calculations in your own method and
call it near the top of your template.  (\code{\#silent}, section
\ref{output.silent}).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Form processing}
\label{webware.form}

There are many ways to display and process HTML forms with Cheetah.
But basically, all form processing involves two steps.
\begin{enumerate}
\item{} Display the form.  
\item{} In the next web request, read the parameters the user submitted,
check for user errors, perform any side effects (e.g., reading/writing a
database or session data) and present the user an HTML response or another
form.  
\end{enumerate}

The second step may involve choosing between several templates to fill (or
several servlets to redirect to), or a big if-elif-elif-else construct to
display a different portion of the template depending on the situation.

In the oldest web applications, step 1 and step 2 were handled by separate
objects.  Step 1 was a static HTML file, and step 2 was a CGI script.
Frequently, a better strategy is to have a single servlet handle both steps.
That way, the servlet has better control over the entire situation, and if
the user submits unacceptable data, the servlet can redisplay the form with a
"try again" error message at the top and and all the previous input filled in.
The servlet can use the presence or absence of certain CGI parameters (e.g.,
the submit button, or a hidden mode field) to determine which step to take.

One neat way to build a servlet that can handle both the form displaying and
form processing is like this:

\begin{enumerate}
\item Put your form HTML into an ordinary template-servlet.  In each input 
    field, use a placeholder for the value of the \code{VALUE=} attribue.
    Place another placeholder next to each field, for that field's error
    message.
\item Above the form, put a \code{\$processFormData} method call.
\item Define that method in a Python class your template \code{\#extend}s.  (Or
    if it's a simple method, you can define it in a \code{\#def}.)  The method
    should:
    \begin{enumerate}
    \item Get the form input if any.
    \item If the input variable corresponding to the submit field is empty,
        there is no form input, so we're showing the form for the first time.
        Initialize all VALUE= variables to their default value (usually ""),
        and all error variables to "".  Return "", which will be the value for
        \code{\$processFormData}.
    \item If the submit variable is not empty, fill the VALUE= variables with
        the input data the user just submitted.
    \item Now check the input for errors and put error messages in the error
        placeholders.  
    \item If there were any user errors, return a general error message
        string; this will be the value for \code{\$processFormData}.
    \item If there were no errors, do whatever the form's job is (e.g., update
        a database) and return a success message; this will be the value for
        \code{\$processFormData}.
    \end{enumerate}
\item The top of the page will show your success/failure message (or nothing
the first time around), with the form below.  If there are errors, the user
will have a chance to correct them.  After a successful submit, the form will
appear again, so the user can either review their entry, or change it and
submit it again.  Depending on the application, this may make the servlet
update the same database record again, or it may generate a new record.
\end{enumerate}

% @@MO: Example of a template that shows a form and then processes the input.

\code{FunFormKit} is a third-party Webware package that makes it easier to
produce forms and handle their logic.  It has been successfully been used with
Cheetah.  You can download FunFormKit from
\url{http://colorstudy.net/software/funformkit/} and try it out for yourself.


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Form input, cookies, session variables and web server variables}
\label{webware.input}

General variable tips that also apply to servlets are in section
\ref{tips.placeholder}.

To look up a CGI GET or POST parameter (with POST overriding):
\begin{verbatim}
$request.field('myField')     
self.request().field('myField')
\end{verbatim}
These will fail if Webware is not available, because \code{\$request}
(aka \code{self.request()} will be \code{None} rather than a Webware
\code{WebKit.Request} object.  If you plan to read a lot of CGI parameters,
you may want to put the \code{.fields} method into a local variable for
convenience:
\begin{verbatim}
#set $fields = $request.fields
$fields.myField
\end{verbatim}
But remember to do complicated calculations in Python, and assign the results
to simple variables in the searchList for display.  These \code{\$request}
forms are useful only for occasions where you just need one or two simple
request items that going to Python for would be overkill.

To get a cookie or session parameter, subsitute ``cookie'' or ``session'' for
``field'' above.  To get a dictionary of all CGI parameters, substitute
``fields'' (ditto for ``cookies'').  To verify a field exists,
substitute ``hasField'' (ditto for ``hasCookie'').  

Other useful request goodies:
\begin{verbatim}
## Defined in WebKit.Request
$request.field('myField', 'default value')
$request.time              ## Time this request began in Unix ticks.
$request.timeStamp         ## Time in human-readable format ('asctime' format).
## Defined in WebKit.HTTPRequest
$request.hasField.myField  ## Is a CGI parameter defined?
$request.fields            ## Dictionary of all CGI parameters.
$request.cookie.myCookie   ## A cookie parameter (also .hasCookie, .cookies).
$request.value.myValue     ## A field or cookie variable (field overrides)
                           ## (also .hasValue).
$request.session.mySessionVar  # A session variable.
$request.extraURLPath      ## URL path components to right of servlet, if any.
$request.serverDictionary  ## Dict of environmental vars from web server.
$request.remoteUser        ## Authenticated username.  HTTPRequest.py source
                           ## suggests this is broken and always returns None.
$request.remoteAddress  ## User's IP address (string).
$request.remoteName     ## User's domain name, or IP address if none.
$request.urlPath        ## URI of this servlet.
$request.urlPathDir     ## URI of the directory containing this servlet.
$request.serverSidePath ## Absolute path of this servlet on local filesystem.
$request.serverURL      ## URL of this servlet, without "http://" prefix,
                        ## extra path info or query string.
$request.serverURLDir   ## URL of this servlet's directory, without "http://".
$log("message")         ## Put a message in the Webware server log.  (If you
                        ## define your own 'log' variable, it will override
                        ## this; use $self.log("message") in that case.
\end{verbatim}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsubsection{.webInput()}
\label{webware.webInput}

From the method docstring:

\begin{verbatim}
    def webInput(self, names, namesMulti=(), default='', src='f',
        defaultInt=0, defaultFloat=0.00, badInt=0, badFloat=0.00, debug=False):

This method places the specified GET/POST fields, cookies or session variables
into a dictionary, which is both returned and put at the beginning of the
searchList.  It handles:
    * single vs multiple values
    * conversion to integer or float for specified names
    * default values/exceptions for missing or bad values
    * printing a snapshot of all values retrieved for debugging
All the 'default*' and 'bad*' arguments have "use or raise" behavior, meaning 
that if they're a subclass of Exception, they're raised.  If they're anything
else, that value is substituted for the missing/bad value.  

The simplest usage is:

    #silent $webInput(['choice'])
    $choice

    dic = self.webInput(['choice'])
    write(dic['choice'])

Both these examples retrieves the GET/POST field 'choice' and print it.  If you
leave off the "#silent", all the values would be printed too.  But a better way
to preview the values is

    #silent $webInput(['name'], $debug=1)

because this pretty-prints all the values inside HTML <PRE> tags.

Since we didn't specify any coversions, the value is a string.  It's a "single"
value because we specified it in 'names' rather than 'namesMulti'.  Single
values work like this:
    * If one value is found, take it.
    * If several values are found, choose one arbitrarily and ignore the rest.
    * If no values are found, use or raise the appropriate 'default*' value.

Multi values work like this:
    * If one value is found, put it in a list.
    * If several values are found, leave them in a list.
    * If no values are found, use the empty list ([]).  The 'default*' 
      arguments are *not* consulted in this case.

Example: assume 'days' came from a set of checkboxes or a multiple combo box
on a form, and the user chose "Monday", "Tuesday" and "Thursday".

    #silent $webInput([], ['days'])
    The days you chose are: #slurp
    #for $day in $days
    $day #slurp
    #end for

    dic = self.webInput([], ['days'])
    write("The days you chose are: ")
    for day in dic['days']:
        write(day + " ")

Both these examples print:  "The days you chose are: Monday Tuesday Thursday".

By default, missing strings are replaced by "" and missing/bad numbers by zero.
(A "bad number" means the converter raised an exception for it, usually because
of non-numeric characters in the value.)  This mimics Perl/PHP behavior, and
simplifies coding for many applications where missing/bad values *should* be
blank/zero.  In those relatively few cases where you must distinguish between
""/zero on the one hand and missing/bad on the other, change the appropriate
'default*' and 'bad*' arguments to something like: 
    * None
    * another constant value
    * $NonNumericInputError/self.NonNumericInputError
    * $ValueError/ValueError
(NonNumericInputError is defined in this class and is useful for
distinguishing between bad input vs a TypeError/ValueError
thrown for some other reason.)

Here's an example using multiple values to schedule newspaper deliveries.
'checkboxes' comes from a form with checkboxes for all the days of the week.
The days the user previously chose are preselected.  The user checks/unchecks
boxes as desired and presses Submit.  The value of 'checkboxes' is a list of
checkboxes that were checked when Submit was pressed.  Our task now is to
turn on the days the user checked, turn off the days he unchecked, and leave
on or off the days he didn't change.

    dic = self.webInput([], ['dayCheckboxes'])
    wantedDays = dic['dayCheckboxes'] # The days the user checked.
    for day, on in self.getAllValues():
        if   not on and wantedDays.has_key(day):
            self.TurnOn(day)
            # ... Set a flag or insert a database record ...
        elif on and not wantedDays.has_key(day):
            self.TurnOff(day)
            # ... Unset a flag or delete a database record ...

'source' allows you to look up the variables from a number of different
sources:
    'f'   fields (CGI GET/POST parameters)
    'c'   cookies
    's'   session variables
    'v'   "values", meaning fields or cookies

In many forms, you're dealing only with strings, which is why the
'default' argument is third and the numeric arguments are banished to
the end.  But sometimes you want automatic number conversion, so that
you can do numeric comparisons in your templates without having to
write a bunch of conversion/exception handling code.  Example:

    #silent $webInput(['name', 'height:int'])
    $name is $height cm tall.
    #if $height >= 300
    Wow, you're tall!
    #else
    Pshaw, you're short.
    #end if

    dic = self.webInput(['name', 'height:int'])
    name = dic[name]
    height = dic[height]
    write("%s is %s cm tall." % (name, height))
    if height > 300:
        write("Wow, you're tall!")
    else:
        write("Pshaw, you're short.")

To convert a value to a number, suffix ":int" or ":float" to the name.  The
method will search first for a "height:int" variable and then for a "height"
variable.  (It will be called "height" in the final dictionary.)  If a numeric
conversion fails, use or raise 'badInt' or 'badFloat'.  Missing values work
the same way as for strings, except the default is 'defaultInt' or
'defaultFloat' instead of 'default'.

If a name represents an uploaded file, the entire file will be read into 
memory.  For more sophisticated file-upload handling, leave that name out of
the list and do your own handling, or wait for Cheetah.Utils.UploadFileMixin.

This mixin class works only in a subclass that also inherits from 
Webware's Servlet or HTTPServlet.  Otherwise you'll get an AttributeError
on 'self.request'.

EXCEPTIONS: ValueError if 'source' is not one of the stated characters.
TypeError if a conversion suffix is not ":int" or ":float".
\end{verbatim}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{More examples}
\label{webware.examples}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsubsection*{Example A -- a standalone servlet}
%\label{}

% @@MO:

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsubsection*{Example B -- a servlet under a site framework}
%\label{}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsubsection*{Example C -- several servlets with a common template}
%\label{}




%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Other Tips}
\label{webware.otherTips}

If your servlet accesses external files (e.g., via an \code{\#include}
directive), remember that the current directory is not necessarily directory
the servlet is in.  It's probably some other directory WebKit chose.  To find a
file relative to the servlet's directory, prefix the path with whatever
\code{self.serverSidePath()} returns (from \code{Servlet.serverSidePath()}.

If you don't understand how \code{\#extends} and \code{\#implements} work, and
about a template's main method, read the chapter on inheritance (sections
\ref{inheritanceEtc.extends} and \ref{inheritanceEtc.implements}).  This may
help you avoid buggy servlets.

% Local Variables:
% TeX-master: "users_guide"
% End:      
%# vim: sw=4 ts=4 expandtab