gettingUCWIntoPlay

ucw Tutorial ucw

Hello welcome back to the new UCW World ;-) Now we have our ucwTutorialDatamodel we know what we want to manipulate in the end (or from where we gather our information).

If you like you can compare it with a webactions based solution at webactionsTutorialStart

Loading UCW

In this section, we will be using components of the UCW library. So before we get started we need to load the UCW library. This is done with ASDF by way of:

 (asdf:oos 'asdf:load-op 'ucw) 

What we want

We want to ask the user for his/her name if the user does not exist yet, we create him. If he/she exists we want to increase his count of current downloads.

Declare a component

The base line of ucw-programming is: 'No component, nothing to view'. A component alone will not help you really it's just the "back" you want to see it also. So nearly every component will come with a render method. For the time being, just think of a Component as a somewhat decorated CLOS-class (there are a few extra things you can include and we'll use them soon).

Now we have to decide what we would like to get and how we are going to get it. We of course need some sort of interaction with the user. So we have to display something to him and he/she may or may not give us back some feedback.

Diverse Components (excursion)

For a list of components see: here.

The thing we are currently interested in has the name simple-window-component

It wraps our input into a frame for a valid xhtml page. So our component will inherit from it. We now have to decide how we want to get the input from the user, HTML does not have many diverse ways to get information from it, AFAICT all are accessible from ucw also. Now the only thing we are interested in is getting a name which we can get e.g with a text field. This is what we'll use also, so our defcomponent could look like this:

(defcomponent get-downloader-name (simple-window-component)
  ((name-input-field 
    :accessor name-input-field
    :initform (make-instance 'string-field
                             :input-size 20
                             :validators (list (make-instance 'not-empty-validator)))) 
   ;; the above is one such extension string-field is a text-field which 
   ;; will get a 'string' as input
   (submit-button :accessor submit-button
                  :initform (make-instance 'submit-button)))
  ;; some like buttons some don't, let us use it to 
  ;; give mouse lovers something to click on
  (:default-initargs
      :title "Downloader")
    (:documentation "A component is a decorated CLOS class you can use 
the same arguments as in 'normal' classes plus some extensions."))

I will try to explain it as I understand it:

* defcompoment is a clos-class with some extra slots which help while displaying something to the user

* the string-field is an object which encapsulates a html text field for us. You do not have to provide a name for it in the way like

 < input name="vorname" type="text" size="30" maxlength="30"> 

this is be done by UCW you access this element either with a reader, accessor or via slot-value. I declared it to have the name name-input-field. I can give you no good suggestion which name you use but it better makes sense to you and you had better be able to remember it for quite a while. How ucw knows which field you are using will be explained later.

Now we have declared some kind of view class, but we have not really done anything to display it. You do have to implement a render generic function specialized on the class you want to display. (and you need some entry point and an application but one after the other ;-)

The render method

The render method could look like this:

(defmethod render((form get-downloader-name))
  (<:h1 "Contact details")
  (<:p "Let us know who you are:")
  (

There nothing very unusual in it. It is specialized on the proper class and it uses an html generator which comes along with ucw. You are not forced to use these html generation facilties, you just have to get a handle to some stream you want to write to (how that is done will be explained later) and use that if you like.

Of course a few things are easier to use with the provided facilities, so for the time being let us stick to it. The above code yields the following html

Output of the rendering function

Ok I hope I get it filled in properly this time.


Downloader

Contact details

Let us know who you are:

Name:

Impressive 3 KB for just one tiny input field, must be the progress I guess.

How does it come?

Wow, that's mighty much for such a small method. I won't get into any details and well I could not really. I have no idea what this dojo.js stuff is about. I do not need it and you can switch off JavaScript also, a few things won't work from there on but that's the JavaScript way. The only thing I like to pick is:

< td class="download-query"
        input id="_ucw_1" name="HepctNzQai" size="20" type="text" value="">

this was emitted from

 (<:td :class "download-query" (render (name-input-field form)))))

This is one of the things I really like about UCW. It keeps this stuff away from me. I do not have to think about a decent name myself I just have to think along CLOS classes, methods accessors. If I ever find the time I will try to explain how I reinvented such stuff myself using webactions.

Another good thing about the name is that it's not to guess it's some random stuff which just happens to have some meaning within my class thinking. So I would argue replay attacks are not a problem with UCW (this safety comes "for free"), but I'm not yet fully sure about it.

How to get this output really?

Now I have presented you something which won't work without some extra setup. Let's do that now.

At first you must declare an Application object, I'm not sure whether this holds really but for me this is a kind of "controller" object in the MVC views. An application object registers an application (the thing we want to display) and sets up our server to react on the part of the URL we registered. As said I'm using apache2 with mod_lisp2 here. You have to set it up to get this running with it. If you feel unsure about this you can ask me or check for the docs from http://www.weitz.de/tbnl/#apache

Create an application

So we have to register an application, I did it this way for this example:

(defvar *downloader-application* nil)

(setf *downloader-application* (make-instance 'cookie-session-application :url-prefix "/ucw/downloader/" ;; :inspect-components t :debug-on-error t))

I used a 'cookie-session-application' this works the following way: You access an URL below the 'url-prefix' and then the server sets a cookie, this is used to identify you, e.g while running the next query. If you have cookies disabled you will see that UCW will keep this information embedded and encrypted in the URL you used to access this application.

I have to admit I prefer the cookie approach, but YMMV. debug on error is a flag which eases debugging, you get a nice backtrace in you (X)Emacs+slime+CL combo and well has helped me sometimes. But be warned the backtraces ucw generetes are difficult to decrpyt (at least for me), the reason seems to be a combination of macros and continuations. You really can despair. But feel free to bother Marco with it .... ;-)

Create a server

See e.g the start.lisp for an example. The default backend in start.lisp is httpd, but there are other backends available. I used the following:

(defun start-server ()
  (ucw:create-server :backend '(:httpd    :host "127.0.0.1" :port 8080 )                              
                     :log-root-directory (make-pathname :name nil :type nil
                                                        :directory "/home/frido/log/")
                     :log-level ucw::+info+
                     :start-p t))

You see you have the choice you can use a lot of different web server backends. The same example has run here with httpd and aserve (have not checked araneida yet), but I prefer the mod_lisp stuff. (I'm not sure but I think Marco did so also, he will have his reasons I guess ;-)

You start the server with

 (start-server) 
feel free to inspect the special variable *default-server*, it's most of the time good to know what's going on.

Register the application

If you forget this you won't see anything you do register this way:

(register-application *default-server* *downloader-application*)

Now come to an end, please

There's one thing left, you have to declare an entry point for you application (be aware Marco and his fellow developers are thinking about a different approach here, I have not used this yet, but maybe I will or will have to in the near future. Now the last step before we see something is:

(defentry-point "get-downloader.ucw" (:application *downloader-application*) ()
  (call 'get-downloader-name))

The application will then be available at the url http://localhost:8080/ucw/downloader/get-downloader.ucw on the machine running the UCW server. Now I decided to introduce this entry-point just to be able to show something to you. What I really had to do to work with the given input, is left out for the moment. I'll try to come back here this week to get you further, I'm really running short on time.

Ok now you enter the mystery world of UCW, not in the sense of applicability but understandability please. Call is a wrapper around the "continuation" stuff which makes UCW unique among the Common Lisp Web frameworks (if I'm wrong about this please correct me), however they are a way of doing things in other languages also. Feel free to check the PLT-Scheme stuff and or the Seaside from Smalltalk.

I have left you a bit alone with this continuations stuff at the moment, I'm still trying to get it myself, if you have question about this you better ask on the bese-devel mailing list http://common-lisp.net/pipermail/bese-devel/

As I understand it, the 'call' stuff means "Stop with whatever you are doing at the moment and goto the component with the name I gave you." This component is then rendered with the render method. So in the end you get the following page ucwTutorialDownloaderWebView (I hope I can place that stuff in the wiki and that it will get rendered.

That's it for today

I now have spent at least 3 hours on these pages to get to this point. If you follow me through the pages you know what we have done so far. * an example description ucwTutorialExample

* setup clsql with a data model ucwTutorialDatamodel

* setup ucw to display something (albeit not very useful)

As written before I try to come back soon and try to get you from one component to an action to another? component.

Feedback is very welcome, but please be a gentle. But if you feel this is sh... feel free to let me know, if you like my writing please let me know.

Have a nice day hacking Friedrich

Next: ucwTutorialGettingFromOnePlaceToAnother ; Previous: ucwTutorialDataModel


This page is linked from: ucw Tutorial   ucwTutorialDataModel   ucwTutorialGettingFromOnePlaceToAnother  

CLiki pages can be edited by anyone at any time. Imagine a fearsomely comprehensive disclaimer of liability. Now fear, comprehensively