Presentation is loading. Please wait.

Presentation is loading. Please wait.

Taming Cocoon ApacheCon Europe 2005 Gianugo Rabellino.

Similar presentations


Presentation on theme: "Taming Cocoon ApacheCon Europe 2005 Gianugo Rabellino."— Presentation transcript:

1 Taming Cocoon ApacheCon Europe 2005 Gianugo Rabellino

2 Agenda  Introduction  Installing Cocoon  Dissecting Cocoon  Management and configuration  A sitemap tour  Cocoon components and blocks  Understanding continuations and flow  Dealing with forms  Patterns, best practices, pitfalls

3 Introduction: web developer nightmares out.println(“ \n\t \n\t\t” + “ ” + request.getParameter(“lousyjob”) + “Does your boss know you\'re typing HTML?” + “ \n\t \n \n”);

4 Nightmare: managing HTML  Your IDE can't deal with HTML  Dreamweaver can't deal with business logic  Period.  Oh, and JSPs suck. Big time. “Separate concerns” - Edsger Dijkstra - 1974

5 Nightmare: handling state  HTTP is stateless (did you notice already?)  Where am I now?  Restart required  Sessions == overpopulated mess of dictionaries

6 Nightmare: managing user input  Validation hell  Conversion ordeal  Binding torture  The infamous Back button, oh my!

7 There has to be a better way “Never let a man do what a machine can do for him” Blaise Pascal

8 Apache Cocoon A fast-paced overview

9 Apache Cocoon: facts and figures  Origins Started by the Italian student Stefano Mazzocchi  Redesign of Apache.org Frustrated by the limitations of HTML Wanted to use emerging technologies (XML/XSL)  Today Now one of the most important Apache projects Incorporates technologies from various project Just under 2000 registered on all mailing lists Includes major companies such as HP, IBM

10 Tucking web devs in, kissing them goodnight

11 10.000ft overview

12  URI space decoupling  Componentized resource assembling  Datasource connections and decoupling  Stateful applications Key Cocoon concepts

13  URI space decoupling Sitemap  Componentized resource assembling Pipelines  Datasource connections and decoupling Source interface and implementations (file, URL, database, WebDAV, XMLDB...)  Stateful applications Web continuations And their implementation...

14  Think on steroids  Pattern freaks think FrontController  Uses pluggable algorithms: Wildcard Regexp Your own  Matching the whole HTTP environment: Request URI/parameters/attributes Session attributes Cookies, context, etc...  Welcome to the sitemap URI space decoupling: the sitemap

15 A sitemap example

16  Task: find the total number of unique hosts visiting the home page of your site Windows solution: #include... Unix solution: $ grep index.html access.log | awk '{print $2 }' | sort | uniq | wc -l  Welcome to the pipeline: specialized components glued together Resource assembling: the pipeline

17  Two simple rules: Data stream is based on SAX events Pipelines start with one Generator (and only one), have 0-n Transformers, end with one (and only one) Serializer  Generators: adapters from the outside world to SAX events  Transformers: SAX event manglers  Serializers: adapters from SAX events to the outside world The Cocoon pipeline

18 A pipeline example

19  Virtualization layer over stream-based data sources  Provides a java.io.File like interface for a number of data sources  Think URLs on steroids Datasource virtualization

20 The Source interface

21 A datasource example

22  The sitemap decouples URI space from physical resources  The pipeline decouples results from the way they're built  XML decouples content from presentation  The source abstraction decouples data sources from physical locations Result: full Separation of Concerns (and you ain’t seen nothing yet...) Summing it up

23 The next revolution Web Continuations

24 Web applications are easy!

25  Webapps are finite state machines  Upon every click, processing starts from the beginning  Again, and again, and again But wait, this is stateless HTTP

26 A typical web application clutter

27 “A continuation is an entire set of closures that make up a point of execution” “A continuation is an object that, for a given point in your program, contains a snapshot of the stack trace, including all the local variables, and the program counter” Hmmm... so what? What are continuations?

28 var cart; var user; function checkout() { while(user == null) { cocoon.sendPageAndWait("login.html"); user = UserRegistry.getUser(cocoon.request.get("name")); } cocoon.sendPageAndWait("shippingAddress.html", {who: user}); var address = cocoon.request.get("address"); cocoon.sendPageAndWait("creditCard.html"); var creditCard = cocoon.request.get("creditCard"); cocoon.sendPageAndWait("confirmOrder.html"); EnterpriseSystem.placeOrder(user, cart, address, creditCard); cocoon.sendPage("orderPlaced.html"); } A flowscript example: where the magic happens

29 – Contents of a continuation ● Stack of function calls ● Value of local variables  Most often a lightweight object  Creating a continuation does not halt a thread !! – A continuation object is associated with a unique identifier available to the view  Later used to "resurrect" it What are continuations, again?

30 saved continuations var cart; var user; function checkout() { while(user == null) { cocoon.sendPageAndWait("login.html"); user = UserRegistry.getUser(cocoon.request.get("name")); } cocoon.sendPageAndWait("shippingAddress.html", {who: user}); var address = cocoon.request.get("address"); cocoon.sendPageAndWait("creditCard.html"); var creditCard = cocoon.request.get("creditCard"); cocoon.sendPageAndWait("confirmOrder.html"); EnterpriseSystem.placeOrder(user, cart, address, creditCard); cocoon.sendPage("orderPlaced.html"); } Flowscript example, revisited

31 var cart; var user; function checkout() { while(user == null) { cocoon.sendPageAndWait("login.html"); user = UserRegistry.getUser(cocoon.request.get("name")); } cocoon.sendPageAndWait("shippingAddress.html", {who: user}); var address = cocoon.request.get("address"); cocoon.sendPageAndWait("creditCard.html"); var creditCard = cocoon.request.get("creditCard"); cocoon.sendPageAndWait("confirmOrder.html"); EnterpriseSystem.placeOrder(user, cart, address, creditCard); cocoon.sendPage("orderPlaced.html"); } Don't fear the Back button anymore! Continuations tree

32 – Continuations give control back to the server  We always know "where" the browser is – Allow sophisticated flow screens  No need for state automata – Increase security and robustness  Forbids direct access to form submission URLs  Handling of "back" and "new window" Summing it up

33 Managing user input A word about forms

34  MVC based form framework  Provides: Strongly-typed data: a date field is a java.util.Date. Automatically. Validation: declarative. Handled for you. Automatically. Binding: to objects (EJB, POJOs...) or to XML, your choice. Automatically. Cocoon Forms: nightmares solved!

35  Separation of Concerns in forms: Model: data typing, validation rules View: widget presentation  selections could be drop down lists or checkboxes Controller:  flowscript (continuations based)  custom actions (à la Struts) – not recommended Data binding:  declarative  JXPath based Cocoon Forms, a functional view

36  Powerful widget library Fields, aggregated fields, dates, selectors, trees and repeaters  AJAX compliant infrastructure Boosts perceived performance  Integrated add-ons HTML editor calendar pop-ups dynamic double selection lists Cocoon Forms: a rich framework

37  Configure, don't code  Continuations make webapp development a breeze  Powerful form frameworks ease managing user input  Separation of Concerns brings maintainability... and they lived happily ever after. Summing it up: RAD development

38 Installing Cocoon Finding your way through compilation and blocks

39 Downloading Cocoon  http://cocoon.apache.org  Subversion for the latest version: http://svn.apache.org/repos/asf/cocoon/branches/BRANCH_2.1.X http://svn.apache.org/repos/asf/cocoon/trunk … or even WebDAV

40 Preparing Cocoon  Task list: Edit local.build.properties  Exclude unneeded and heavy tasks (e.g. javadocs / documentation) Edit local.blocks.properties  Beware of dependencies  All done, now run: $./build.sh (Unix) C\> build.bat (Windows)

41 Testing the install  Embedded Jetty: Run $./cocoon.sh servlet (Unix) C\> cocoon.bat servlet (Windows) Point your browser to http://localhost:8888/  Other servlet engines: Run $./build.sh war (Unix) C\> build.bat war (Windows) Deploy dist/cocoon*.war

42 Beware the classloader  Cocoon uses its own version of Rhino (Javascript engine)  Might clash with vendor-provided ones (e.g. Websphere/BEA)  Make sure that your appserver is configured to run Cocoon in an isolated classloader (as per servlet spec): ask your vendor to fix his bug if it doesn’t work  If it doesn’t work, use the “paranoid” block and the ParanoidCocoonServlet (but you shouldn’t)  Mind redirects on WebSphere!

43 Eclipse integration  Run: $./build.sh eclipse-project (Unix) C\> build.bat eclipse-project (Windows)  Inside Eclipse: New Java Project Navigate to $COCOON_HOME  Your project will appear automagically!

44 Files you want to know  Main sitemap: $COCOON_HOME/build/webapp/sitemap.xmap  Log configuration: $COCOON_HOME/build/webapp/WEB-INF/logkit.xconf  Component configuration: $COCOON_HOME/build/webapp/WEB-INF/cocoon.xconf  Mount table: $COCOON_HOME/mount-table.xml

45 Management and configuration Handling Cocoon in production

46 Configuring Cocoon  Web Application Configuration Cocoon runs as a servlet Configuration controlled by web.xml Find it in the WEB-INF directory  Most important entry Name and location of the actual configuration file  Default: WEB-INF/cocoon.xconf configurations /WEB-INF/cocoon.xconf

47 Configuring Cocoon  cocoon.xconf XML format Contains Avalon component configuration But not (!!) the sitemap components  They are in the sitemap cocoon.xconf rarely needs changing  Moving from test to production  Replacing the XML parser

48 Configuring Cocoon  cocoon.xconf ...

49  cocoon.xconf No namespace Each component defined inside Logical names matched to implementations  e.g. parser ; hsqldb-server Configuration using  Contains name-value pairs pool-min and pool-max  We will look at those later (pooling) Configuring Cocoon

50  cocoon.xconf Another important piece of information  Location and name of the sitemap Reloading  Triggers on incoming request  Synchronous New sitemap will be generated and then handles the request  What do you do if an error occurs............

51 Configuring Cocoon  LogKit Configuration Each component in Cocoon logs using LogKit There are five log levels  DEBUG  INFO  WARNING  ERROR  FATAL_ERROR In testing: DEBUG In production: ERROR or FATAL_ERROR Location of the LogKit configuration file  Is in the web.xml: logkit-config /WEB-INF/logkit.xconf

52 Configuring Cocoon  LogKit Configuration Consists of several parts  Factories for logging targets Implementations are not "hard-wired" Defines components that are to receive the log messages  Targets Configured with Factory And file name, output format, size/rotation information  Categories Actual "receiver" of the log messages Configured with (multiple) targets And log level

53 Configuring Cocoon  LogKit Configuration ${context-root}/WEB-INF/logs/cocoon.log %7.7{priority} %{time} [%8.8{category}] (%{uri}) %{thread}/%{class:short}: %{message}\n%{throwable} true 100m 01:00:00

54 Configuring Cocoon  LogKit Configuration (Normally) No need to change the setting  Apart from log-levels  Not reflected automatically  Touch cocoon.xconf DEBUG logfiles can become very large  Hard drives have a limited capacity  And slow performance down Default level: ERROR for all categories

55 Dissecting Cocoon A sitemap tour

56 Cocoon anatomy

57 Cocoon physiology

58 The sitemap disemboweled  The sitemap contains: Component definitions and configurations Views Resources Action sets Flow Pipelines  … all neatly packaged as a namespaced XML file

59 Sitemap components  Configured as children of the section  Contains: Generators Transformers Serializers Readers Matchers Selectors Actions Pipes …and their configuration  Each section declaration can have a default component

60 Sitemap components Tour  Generator, Transformers and Serializers are typical Cocoon components for pipelines  Readers are used for binary resources Think of a “collapsed” Generator and Serializer  Matchers are used to route requests  Selectors implement branching (if… then… else) logic  Actions implement business logic based switching (old fashioned, flow is now the preferred way)  Pipes define different pipeline implementation (which differ mainly for caching policies)  Examples will follow

61 A word about Actions  Actions are reusable snippets of business logic  Actions wrap pipeline snippets  Actions can return either: null : the pipeline snippet is skipped A Map containing business values, which can be reused in the pipeline snippet

62 Sitemap components example false false false xalan true

63 Tip: reusing components  Components can be re-defined with different configurations,  Names have to be unique false false false xalan true false false false xsltc true

64 Understanding views  Views are “exit points” in pipeline processing  Original motivation: semantic search  Current use: mainly debug  Configuration: name : unique identifier from-label : explicit exit point from-position : implicit (automatic) exit point  first : right after the generator  last : right before the serializer  Activated by cocoon-view=view-name  Warning! Views are not inherited by subsitemaps  Warning! Views can be a security concern

65 More on views: placing labels  Labels are set using the label attribute on either: A Generator or Transformer declaration in the components section (will work anywhere) A Generate or Transform directive in a pipeline (specific to the pipeline) An Aggregate or Part directive (more on this later)

66 View examples  Defining views:  Defining labels:

67 Resources  Reusable pipeline fragments  Useful for repetitive tasks  Will be (mostly) replaced by Virtual Sitemap Components  Warning! Resources are not inherited by subsitemaps

68 A resource example  Defining a resource:  Calling a resource

69 Action-sets  Define a set of actions to be executed as a unit of work either: Unconditionally (upon every invocation) When explicitely called, using a cocoon-action parameter

70 Declaring flow scripts  Flow is a new way to insert page flow control in your application (much more on that later)  Scripts and/or classes are declared in the flow section of the sitemap

71 The pipelines section  The “heart” of Cocoon, where things get done  Contains 1+ declarations  Any pipeline section represents a logical division  Different pipelines serve different purposes: Visibility: internal-only pipelines can only be just using the cocoon : protocol; Caching, as pipelines can be:  non-cached (always executed)  cached delegating validity to the pipeline components (executed if nothing has changed in the pipeline)  cached beforehand using the expires directive (executed only once during the validity period)

72 Cocoon pipelines dissected  Pipelines are “recipes” building resources  SAX events travel through the pipeline  The TLA is GTS: Generator, Transformer, Serializer  Generators are adapters from the outside world to SAX events  Transformers are SAX filters  Serializers are the opposite of Generators, adapting SAX events to the outside world  The obligatory diagram:

73 What’s in a pipeline?  Well, components in action: from nouns to verbs  Content production: generate [- transform ] - serialize aggregate - part [ - part …] read  Branching: match select act call

74 So what’s the sitemap, again?  Central switchboard (or FrontController, if you like patterns)  Contains component declarations (yes, even business components)  Locates (match) and builds (pipelines) the final result  In most cases, it’s the only file you’ll need to touch

75 A typical request cycle in Cocoon 1. The environment is checked for the proper pipeline to use (normally via matching/selecting) 2. The pipeline is evaluated: 1. Sitemap components are looked up via type references or default assignment 2. The pipeline is setup. 3. The pipeline is executed Warning: no dynamic sitemap routing!

76 Zen and the art of matching

77 A perfectly valid pipeline example  Would match any request and greet the user  … which is probably not what you want

78 Matchers kick in  Matchers associate the actual environment to a pipeline  Hit http://localhost:8888/hello

79 Semantic problem  Warning, pitfall ahead! Formally a pipeline is everything included in Colloquially, though, a pipeline is normally the G-T-S part

80 Why the fuss?  A pipeline, formally, is everything that starts with a Generator and ends with a Serializer  This sample, then, is perfectly valid: 1: 2: 3: 4: 5: 7: 8: 9: 10:

81 To make things further complicated…  This one is valid as well: 1: 2: 3: 4; 5: 6: 7: 8: 9: 10: 11: 12:

82 Argh! Where is my aspirin?  … but this one could not be: 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:

83 Bottom line  Cocoon will process the sitemap and try to build a G-[T]-S pipeline  Cocoon will stop processing when a Serializer is met  Beware the “Generator already set” errors!  You can’t have a “Serializer already set” error

84 Understanding matchers  Matchers will “route” a user request through Cocoon pipelines  Matchers are evaluated in order: first match wins  Matchers are available for the whole environment, matching on: Request URI Request parameters Request Attributes Session Attributes Cookies … and more  Matchers are pluggable: write your own!

85 Using matchers  A basic example:  Captures an empty URI

86 Wildcard-based matching  Wildcard match part of the URI using special chars ( */** )  A single asterisk matches everything up to the first forward slash Matches http://localhost:8888/welcome-friend  A double asterisk matches everything Matches http://localhost:8888/welcome/friend

87 Capturing matcher results  Captured parts of a URI are available for later use  Ordered list, denoted by position number in curly braces  Starts at 1 Matches http://localhost:8888/welcome-friend Uses welcome-files/friend.xml as the generator input  Can be arbitrarily complex:

88 Nesting matchers  Matchers can be nested:

89 Nesting matchers: capturing parent results  The matched expression on the child matcher doesn’t take into account the part already matched  “Parent” captured expressions are available with a tree navigation syntax:

90 Dealing with Sources

91 The Source abstraction  Abstracts a stream based data source  Sub interfaces define write mode and tree-like navigation (à la java.io.File )  URL-like syntax (with some bastardization)

92 The Source interface

93 Available sources  Remote sources: URLSource: deals with every protocol available for java.net.URL FileSource: manages local files WebDAVSource: interoperates with WebDAV repositories XMLDBSource: connects to NXDs BlobSource: uses databases blobs  “Meta” sources: SitemapSource: uses Cocoon pipelines as data stream sources ResourceSource: grabs data from classpath ContextSource: accessed streams from the webapp context ModuleSource: converts modules into sources CachedSource: decorates sources adding passive caching

94 The Sitemap Source  Calls cocoon pipelines  Weirdo: When used in a generator or transformer, the called pipeline serializer will be ignored When used in a reader, the serializer will be honored  More weirdos: URL bastardization cocoon:/ will call a pipeline starting from the current sitemap cocoon:// will call a pipeline starting from the root sitemap

95 Cocoon Components Tour A journey through Generators, Transformers, Serializers, Readers, Matchers, Sub-sitemaps, Modules, Error handling and more

96 Components Tour  Cocoon has roughly 400 components: 66 Generators 65 Transformers 23 Serializers 10 Readers 37 Matchers 31 Selectors 88 Actions 59 Input/Output Modules  And you might want to write your own  No way to cover them all… we’ll see the most useful

97 Useful stuff: FileGenerator  Actually it’s a SourceGenerator: can deal with every Source data stream  … which includes cocoon:// URIs  Probably the most used generator in Cocoon

98 Useful stuff: Directory Traversal  Operate on TraversableSources (directories)  Provide an XML listing of the requested resources  Available components: DirectoryGenerator  ImageDirectoryGenerator  MP3DirectoryGenerator TraversableGenerator TraversableSourceDescriptionGenerator XPathTraversableGenerator

99 Useful stuff: more generators  JXTemplateGenerator: inspired by JSTL, more on this later  RequestGenerator: XMLized Request object  SessionAttributeGenerator: streams an object stored in session as XML  StreamGenerator: reads and streams XML from a request InputStream (e.g. POST requests)  HttpProxyGenerator: accesses an XML stream over HTTP  HTMLGenerator: grabs HTML from a source, converts to XHTML using jTidy and streams it away

100 Useful stuff: TraxTransformer  Can use either (and concurrently): TRAX Xalan Saxon  Relevant configuration parameters: true|false trax|xalan|xsltc true  Beware caching impact!

101 Useful stuff: I18NTransformer  Incredibly useful for dictionaries and localization  Golden rule: use it  Relevant configuration: translations/tiered translations true

102 Dissecting I18NTransformer  Resolving catalogue files: name, id: unique identifiers and base names for files location: a source to be prepended to the base names Locale will be appended, in full or short form (en_US or en as a fallback). Finally, “.xml” will complete the file name  So:  Assuming “en_US” as locale, the transformer will look for: translations/messages_en_US.xml translations/messages_en.xml translations/messages.xml

103 I18N catalog files Apache Cocoon i18n Samples Samples Introduction Static (XML) Dynamic (XSP) Sitemap source Locales Documentation docs]]> Javadoc]]> Javadoc]]> Credits Konstantin Piroumian Many others...

104 Using the I18NTransformer  From then you can happily translate:  Elements titletext  Attributes  Dates  Numbers

105 Useful stuff: CIncludeTransformer  Dynamically inserts content in XML streams  Reacts to elements in the http://apache.org/cocoon/include/1.0 namespace Hello This is my first Cocoon page!  Can be cached as well:

106 Useful stuff: SourceWritingTransformer  Useful to write XML data to (Writeable) Sources during pipeline execution e.g., save a file  Reacts to elements in the http://apache.org/cocoon/source/1.0 namespace  Typically used with XSLT building the source:* stuff  Read the Javadocs for details file://tmp/test.write a title...

107 Useful stuff: XMLSerializer  Outputs, well, XML.  Configurable encodings and doctypes: -//W3C//DTD XHTML 1.1//EN http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd UTF-8

108 Useful stuff: FOPSerializer  Uses Apache FOP to produce: PDF PS PCL RTF WEB-INF/fop-config.xml true

109 Useful stufff: SVGSerializer  Takes SVG as input, produces JPEG/PNG as output  Uses Apache Batik

110 Useful stuff: ImageReader  Will serve images (surprise!)  The kick: performing width, height, ratio adjustments (great for thumbnails)

111 Sub sitemaps  Sitemaps could become overpopulated and messy (the Perl effect)  Solution: modularize using sub-sitemaps  From the main sitemap match the parent path and mount a sitemap underneath:  Wildcard substitution, of course, works:

112 Input/Output Modules  Modules create generic components and plug actual input/output at runtime  Example: grab a request parameter and use it in the sitemap  Again: no dynamic routing possible Modules are evaluated during the pipeline setup phase

113 Useful modules: GlobalInputModule  Allows to configure global variables in the sitemap, with runtime substitution  Helps writing maintainable code webdav://localhost/webdav/step1/

114 Useful modules: XMLFileInputModule  Allows XPath queries on external resources  Helps maintainability: configuration will be outside the sitemap  Configured in cocoon.xconf …

115 When things go wrong: error handling  Error conditions (exception) can be catched in the pipeline  Each pipeline can have a handle-errors section  Error handling is inherited  NotifyingGenerator provides errors in XML format  ExceptionSelector allows branching according to the exception

116 Error handling explained

117 Flowscript The magic of web continuations

118 Introduction JavaScript features View layer Putting it all together Session variables Managing continuations Overview

119  Need for flow control What is "flow control" ?  Control of transition between pages  Driven by application logic Aren't actions enough ?  Yes, but they require state management  Quickly becomes complex, hard to understand and to maintain Introduction

120  Flow script : what is it ? Simple and effective way to glue together business logic, presentation and page flow Uses scripts written in JavaScript (server-side)  a simple scripting language  can implement the most complex use cases Why JavaScript ?  Simpler than Java, although powerful  Integrates well with Java  Well-known in the web world  Allows faster roundtrips (save and reload)  Supports continuations Introduction

121  Flow script example var cart; var user; function checkout() { while(user == null) { cocoon.sendPageAndWait("login.html"); user = UserRegistry.getUser(cocoon.request.get("name")); } cocoon.sendPageAndWait("shippingAddress.html", {who: user}); var address = cocoon.request.get("address"); cocoon.sendPageAndWait("creditCard.html"); var creditCard = cocoon.request.get("creditCard"); cocoon.sendPageAndWait("confirmOrder.html"); EnterpriseSystem.placeOrder(user, cart, address, creditCard); cocoon.sendPage("orderPlaced.html"); } var cart; var user; function checkout() { while(user == null) { cocoon.sendPageAndWait("login.html"); user = UserRegistry.getUser(cocoon.request.get("name")); } cocoon.sendPageAndWait("shippingAddress.html", {who: user}); var address = cocoon.request.get("address"); cocoon.sendPageAndWait("creditCard.html"); var creditCard = cocoon.request.get("creditCard"); cocoon.sendPageAndWait("confirmOrder.html"); EnterpriseSystem.placeOrder(user, cart, address, creditCard); cocoon.sendPage("orderPlaced.html"); } Introduction

122  JavaScript vs. Java detour If you know Java, you already know JavaScript ! Well, mostly. JavaScript is dynamically typed (variables don’t have types, values do) Prototype-based inheritance as opposed to class-based inheritance Objects are extensible at runtime : add or remove properties and methods Introduction

123  cocoon.sendPage() cocoon.sendPage invokes the output page (view) with two arguments  The view URL, relative to current sitemap  A context Map made available to the view  Can contain Java or JavaScript objects cocoon.sendPage("view.html") is like redirecting to "cocoon:/view.html" Control then comes back to the script  Should normally terminate cocoon.sendPage("checkout.html", {user: loggedUser, email: address}); cocoon.sendPage("checkout.html", {user: loggedUser, email: address}); Calling the view

124  cocoon.sendPageAndWait() Similar to cocoon.sendPage  Invoke the view with a context object The script is suspended after the view is generated  the whole execution stack saved in a continuation object Flow between pages becomes sequential code  No more complicated state automata Calling the view

125  What is it ? Contents of a continuation  Stack of function calls  Value of local variables  Most often a lightweight object  Creating a continuation does not halt a thread !! A continuation object is associated with a unique identifier available to the view  Later used to "resurrect" it Continuations

126  Sample flow script revisited saved continuations var cart; var user; function checkout() { while(user == null) { cocoon.sendPageAndWait("login.html"); user = UserRegistry.getUser(cocoon.request.get("name")); } cocoon.sendPageAndWait("shippingAddress.html", {who: user}); var address = cocoon.request.get("address"); cocoon.sendPageAndWait("creditCard.html"); var creditCard = cocoon.request.get("creditCard"); cocoon.sendPageAndWait("confirmOrder.html"); EnterpriseSystem.placeOrder(user, cart, address, creditCard); cocoon.sendPage("orderPlaced.html"); } var cart; var user; function checkout() { while(user == null) { cocoon.sendPageAndWait("login.html"); user = UserRegistry.getUser(cocoon.request.get("name")); } cocoon.sendPageAndWait("shippingAddress.html", {who: user}); var address = cocoon.request.get("address"); cocoon.sendPageAndWait("creditCard.html"); var creditCard = cocoon.request.get("creditCard"); cocoon.sendPageAndWait("confirmOrder.html"); EnterpriseSystem.placeOrder(user, cart, address, creditCard); cocoon.sendPage("orderPlaced.html"); } Continuations

127  What is JXTemplate ? An XML template language inspired by JSTL Doesn't allow code, but only access to context variables  More simple, more secure Flow values are provided as variables : 2 expression languages : Jexl and JXPath Name: Name: Continue View layer : JXTemplate

128  Jexl JSTL & Velocity's expression language  JavaBean property navigation language  Property navigation using "."  Expressions enclosed in ${…}  More suited to Java objects You are calling from ${request.remoteHost} http://jakarta.apache.org/commons/jexl/ View layer : JXTemplate

129  JXPath XPath on abitrary object graphs  XML documents, but also JavaBeans  Expressions enclosed in #{…}  Equally suited to XML documents and Java objects You are calling from #{$request/remoteHost}  http://jakarta.apache.org/commons/jxpath/ View layer : JXTemplate

130  The sitemap …/… …/… Ressurect a continuation Called by the flow Call a flow function Putting it all together

131  Recap Controller is composed of flow scripts written in JavaScript  use sendPageAndWait() to send a response and temporarily suspend execution Views are regular pipeline with access to flow data  JPath XSP tag library  JXTemplate generator Model : your Java business logic Sitemap glues everything together Putting it all together

132  Access to the environment "request", "response", "session " and "context" properties "parameter" : sitemap parameters  Access to the framework Logging :"log" property  cocoon.log.debug("Hi there"); Getting components  cocoon.getComponent("org.apache.excalibur.xml.Parser")  cocoon.releaseComponent(parser) The "cocoon" global object

133  Script modularization JavaScript has no "import" feature  cocoon.load("resource://other/script.js")  Page flow control cocoon.sendPage(), cocoon.sendPageAndWait()  Internal calls to the sitemap cocoon.redirectTo("foo.html")  External redirect sent to the browser The "cocoon" global object

134  Global scope = session scope Global variables are attached to the session  Saved across top-level function invocations  Specific to each user  Removes most of the needs for session attributes ! Session variables

135  Example var user = null; function login() { while (user == null) { sendPageAndWait("login.html"); user = UserRegistry.getUser( cocoon.request.getParameter("name"), cocoon.request.getParameter("password") ); } function placeOrder() { login(); Accounting.placeOrder(user); sendPage("orderPlaced.html"); } function logout() { user = null; sendPage("bye.html"); } var user = null; function login() { while (user == null) { sendPageAndWait("login.html"); user = UserRegistry.getUser( cocoon.request.getParameter("name"), cocoon.request.getParameter("password") ); } function placeOrder() { login(); Accounting.placeOrder(user); sendPage("orderPlaced.html"); } function logout() { user = null; sendPage("bye.html"); } Shows the login screen only if needed Won't pass through if not logged ! Just clear user info to log out Session variables

136 var cart; var user; function checkout() { while(user == null) { cocoon.sendPageAndWait("login.html"); user = UserRegistry.getUser(cocoon.request.get("name")); } cocoon.sendPageAndWait("shippingAddress.html", {who: user}); var address = cocoon.request.get("address"); cocoon.sendPageAndWait("creditCard.html"); var creditCard = cocoon.request.get("creditCard"); cocoon.sendPageAndWait("confirmOrder.html"); EnterpriseSystem.placeOrder(user, cart, address, creditCard); cocoon.sendPage("orderPlaced.html"); } var cart; var user; function checkout() { while(user == null) { cocoon.sendPageAndWait("login.html"); user = UserRegistry.getUser(cocoon.request.get("name")); } cocoon.sendPageAndWait("shippingAddress.html", {who: user}); var address = cocoon.request.get("address"); cocoon.sendPageAndWait("creditCard.html"); var creditCard = cocoon.request.get("creditCard"); cocoon.sendPageAndWait("confirmOrder.html"); EnterpriseSystem.placeOrder(user, cart, address, creditCard); cocoon.sendPage("orderPlaced.html"); }  Continuation trees Browser "back" or "new window" … Managing continuations

137  Continuation trees Browser "back" : the previous path is lost No fear : a continuation is lightweight  Reference to the parent continuation  Local variables since the parent continuation Browser "new window"  Creates a new branch  Allows "what if ?" navigation in the application Managing continuations

138  Expiring continuations Manual expiration :  sendPageAndWait() returns its continuation k  k.invalidate() invalidates the continuation and its subtree  Again, avoids complicated state management Automatic expiration  An inactive continuation expires after a delay var k = sendPageAndWait("start.html");... BusinessService.commit(); // Cannot go back again k.invalidate(); var k = sendPageAndWait("start.html");... BusinessService.commit(); // Cannot go back again k.invalidate(); Managing continuations

139  Flow script Gives control back to the server  We always know "where" the browser is Allows sophisticated flow screens  No need for state automata Increases security and robustness  Forbids direct access to form submission URLs  Handling of "back" and "new window" Conclusion

140  Flow script debugger Activated in cocoon.xconf Development tools

141 Dealing with forms The powerful Cocoon forms framework

142 Introduction  The need for form handling Cocoon started as a publication framework  Many pages, limited user feedback  Content was mostly written "outside" Evolution towards a general-purpose web framework  Published content has to be managed  Used for more and more data-centric applications  Need for good form handling features  Various attempts before Cocoon Forms…

143 Cocoon Forms principles  Main requirements Strong typing and formatting  A date input will give a java.util.Date  Support for localized input formats No requirement for a form bean  The form has its own data model Easy and safe binding to the data model  Only when the all inputs are valid  No direct link from request to application data Strong separation of form definition and styling Extensibility  Everything is a component

144 Cocoon Forms principles  The big picture

145 Cocoon Forms principles  The form object model Composed of "widgets"  Represents "something" that appears in the form  Can read, parse and validate itself  Can output its XML representation public interface Widget { public Widget getParent(); public void setParent(Widget widget); public Widget getWidget(String id); public String getId(); public String getFullyQualifiedId(); public void readFromRequest(FormContext formContext); public Object getValue(); public void setValue(Object object); public boolean validate(FormContext formContext); public void generateSaxFragment(ContentHandler contentHandler, Locale locale); public void generateLabel(ContentHandler contentHandler); } public interface Widget { public Widget getParent(); public void setParent(Widget widget); public Widget getWidget(String id); public String getId(); public String getFullyQualifiedId(); public void readFromRequest(FormContext formContext); public Object getValue(); public void setValue(Object object); public boolean validate(FormContext formContext); public void generateSaxFragment(ContentHandler contentHandler, Locale locale); public void generateLabel(ContentHandler contentHandler); } Widget hierarchy Naming Parsing and validation XML output

146 Cocoon Forms principles  Form definition overview Name: Email address: …/… Name: Email address: …/…

147 Cocoon Forms principles  Form template overview Embeds widget references in target markup Registration form Registration …/… Registration form Registration …/…

148 Cocoon Forms principles  Resulting output

149 The form definition file  Widgets Standard widgets  : the main form widget  : "atomic" input field  : boolean input  : multiple selection in a list  : collection of widgets  : unmodifiable widget  : action button  : a tree-shaped widget They're all defined in cocoon.xconf  Add your own if needed

150 The form definition file  The widget Definition overview The label can contain abitrary markup  Including i18n references... [...] [...]... [...] [...] Your name

151 The form definition file  Defining the data type of a field Mandatory "base" type  Defines the Java type  "string", "long", "decimal", "date", "boolean"  Pluggable components : add your own ! Optional conversion and validation [...] [...] [...] [...] Parsing and formatting Validation

152 The form definition file  Data type parsing and formatting Each base type has a set of converters  Pluggable components : add your own ! Example : date's "formatting" converter  based on java.text.SimpleDateFormat  locale-dependent patterns yyyy-MM-dd MM/dd/yyyy dd/MM/yyyy dd.MM.yyyy yyyy-MM-dd MM/dd/yyyy dd/MM/yyyy dd.MM.yyyy

153 The form definition file  Data type validation A validation rule checks value validity  length, range, regexp, creditcard, assert, email  Pluggable components : add your own ! A datatype can have several validation rules  Example : email input field Not a valid email address! Not a valid email address!

154 The form definition file  Selection lists Provide enumerations to the user  List of items having a value  Optional item label Selection lists can be external and dynamic

155 The form definition file  The widget Boolean values  Usually rendered as a checkbox Put me on or off. Put me on or off.

156 The form definition file  The widget Allows the selection of several values  The value is an Object[]  Requires a Indicate your 2 most preferred drinks: Indicate your 2 most preferred drinks:

157 The form definition file  The widget Repeats a number of child widgets  Used to manage collections, tables, etc. Firstname Lastname Firstname Lastname

158 The form definition file  The widget Read-only widget  Provides formatting features  But doesn't read its value from the request

159 The form definition file  The widget An action button other than standard "submit"  Allows various actions to be taken on the form  "action-command" defines the event name Firstname Lastname Add contact Remove selected contacts Firstname Lastname Add contact Remove selected contacts

160 The form template  The big picture (again)

161 The form template  Role of the Cocoon FormsTransformer "Expand" all ft: elements Registration form Registration …/… Registration form Registration …/… Registration form Registration Name: Name: Cocoon Email address: Email address: foo Invalid email address …/… Registration form Registration Name: Name: Cocoon Email address: Email address: foo Invalid email address …/… Validation failed

162 The form template  Role of the FormsTransformer Expand all "ft" elements in their "fi" counterpart  ft = Cocoon Forms template  fi = Cocoon Forms instance Output of the transformer goes to styling  Provided : HTML styling  Other stylings are possible (e.g. WML)  Cocoon Forms does not hardcode the presentation !

163 The form template  The element Setup the transformer context  Retrieve the Form object from the environment  The element Copies the content of  Used to separate label output from the full widget

164 The form template  The element Produces the corresponding widget instance  Markup depends on the actual widget  For fields :,, can contain styling information  Drives the styling stylesheet  Contents of depends on the styling !

165 The form template  The element Iterates on the contents of a  Use to build e.g. tables  Produces indexed names for each iteration  Gets the label of a child of the repeater  Useful for table headers

166 The form template  The element Name Email address Name Harry Email address harry@potter.com Name Anakin Email address anakin@sw.com Name Email address Name Harry Email address harry@potter.com Name Anakin Email address anakin@sw.com

167 Built in HTML styling  The provided stylesheets »forms-field-styling.xsl"  Only styles basic inputs (fields & actions)  many styling variants »forms-advanced-field-styling.xsl »  Advanced group layout  fieldsets, tab panels, overlapping panels

168 Built in HTML styling  Field styling Basic styling : html input  "password"   "hidden"   "textarea"   "date"  date popup

169 Built in HTML styling  Fields with a Basic styling : drop-down menu  "listbox"  …  "radio"  Additional "orientation" attribute (horizontal/vertical)  Basic styling : check-boxes

170 Built in HTML styling  Instance-only widget providing high-level styling  No corresponding nor  Contains items that will be laid out Profile header Profile header

171 Built in HTML styling  styling Contents rendering  "layout" attribute : "columns"  Automatic 2-column layout of widgets and labels type="fieldset" layout="columns" Profile header [...] Profile header [...]

172 Built in HTML styling  styling Container rendering  "type" attribute : "fieldset", "tabs", "choice"  Tabs defined with CSS type="choice" type="tabs" Note : items in "tabs" and "choice" are most often subgroups

173 Binding : linking forms to application data  An additional binding definition file Associates widget names to XPath expressions on the data model Example : binding to an XML document Set the context of included paths Associates a widget to a path Read-only widget Binding convertor (XML is text)

174 Usage in flow script  The form.js library Provides a Form class  Constructor takes a form definition file Method Form.showForm() to display the form  Does not return until validation is ok !!  Internal loop on sendPageAndWait() function edit_header() { var form = new Form("forms/profile-header-def.xml"); form.showForm("view-profile-header.html", {foo: bar}); var revision-date = form.getModel().releaseDate;... sendDialog("Thanks a lot"); } function edit_header() { var form = new Form("forms/profile-header-def.xml"); form.showForm("view-profile-header.html", {foo: bar}); var revision-date = form.getModel().releaseDate;... sendDialog("Thanks a lot"); } Application data for the view Getting form data

175 Usage in flow script  Advanced features Business-level validation  Because not all constraints can be in the definition file Knowing the that was hit function edit_header() { var limit = Application.getLimit(); var form = new Form("forms/profile-header-def.xml"); form.validator = function(form) { var dateWidget = form.getWidget("releaseDate"); if (dateWidget.getValue() > limit) { dateWidget.setValidationError("Out of limits"); return false; } return true; } form.showForm("view-profile-header.html", {foo: bar}); if (form.submitID == 'cancel') { sendDialog("Action cancelled"); } else { var revision-date = form.getModel().releaseDate;... sendDialog("Thanks a lot"); } function edit_header() { var limit = Application.getLimit(); var form = new Form("forms/profile-header-def.xml"); form.validator = function(form) { var dateWidget = form.getWidget("releaseDate"); if (dateWidget.getValue() > limit) { dateWidget.setValidationError("Out of limits"); return false; } return true; } form.showForm("view-profile-header.html", {foo: bar}); if (form.submitID == 'cancel') { sendDialog("Action cancelled"); } else { var revision-date = form.getModel().releaseDate;... sendDialog("Thanks a lot"); } Form is redisplayed if result is false Test of the submit button

176 Usage in flow script  Advanced features Binding form and application data function edit_header() { var data = Application.getData(); var form = new Form("forms/profile-header-def.xml"); form.createBinding("forms/profile-header-binding.xml"); form.load(data); form.showForm("view-profile-header.html", {foo: bar}); form.save(data); sendDialog("Thanks a lot"); } function edit_header() { var data = Application.getData(); var form = new Form("forms/profile-header-def.xml"); form.createBinding("forms/profile-header-binding.xml"); form.load(data); form.showForm("view-profile-header.html", {foo: bar}); form.save(data); sendDialog("Thanks a lot"); }

177 Putting it all together : the sitemap  HTTP method selection GET method : start the flow POST method : continue Advantages  The form's action is "" (submit to the same URL)  Continuation management is hidden

178 Putting it all together : the sitemap  View pipeline Use of JXTemplate generator  Allows the use of application data passed to showForm() Or just a plain file generator, using the template

179 Conclusion A powerful form framework  Rich datatypes and validation rules  Easy extension to specific needs Flow script makes it really easy Future work  Client-side validation  Better event handling system  Overall stabilization Detailed documentation on http://wiki.cocoondev.org/Wiki.jsp?page=CForms

180 Summary  Good for complex / multi forms  Widget Oriented Approach Custom validation rules Dependencies Strongly type data  Separation of declarations and templates Modular Reuse  Business Integration via Flow  I18n Support

181 Tales from the operation room 8 simple rules for building a manageable Cocoon applications

182 Cocoon and manageability  Cocoon is a huge beast to master  Things tend to get out of hands quickly  The real Cocoon advantage is about increased manageability So plan for it

183 Plan, plan, plan  Don’t start coding, start sketching  Customize the Cocoon environment: Be ruthless in excluding blocks Have a solid build system Use mount-table wisely Do version control local.build.properties and local.blocks.properties

184 Manage configuration files  You will need to modify configuration files: Use Cocoon’s own XConfTool to patch Cocoon configurations Separate configuration (patch) files by functionality Have further configuration files to overcome the current Cocoon blocks limitations (why do you need JMS to access WebDAV?) Don’t trust components in Cocoon’s main sitemap, declare them again

185 Relocation is not an option  Users might install your application in a number of ways: Directly from the webapp root From a context path As a sub-sitemap  Resource resolving needs to take this into account: Use a mount-point variable Perform calculations (upcoming Cocoon versions)

186 Samples are just samples  Don’t rely on them for any functionality  Import the required resources, don’t link to them  This is especially true for Cocoon Forms Newer Cocoon versions have Forms resources packaged in a jar file However, XSLTs are still included in samples

187 Separate application and user concerns  In most applications, users are supposed to manage configuration files  Keep user-accessible resources separated: Client-side CSS, JS, images Consider xsl:import (with performance in mind) as override mechanism

188 Package and ship  Ideally, package everything in a jar file  Yes, even sitemaps:  Don’t forget: Error management ( map:handle-errors ) Error logging ( logkit.xconf )

189 Wrapping up  Long journey, and bumpy ride  Yet barely scratched the surface  More Cocoon presentations during ApacheCon: DE1348: Tools for Content Management and Publishing in Apache: An Overview DE1258: Single Source Publishing with Apache Forrest DE1221: Cocoon - One Hour Portal DE1244: Developing Enterprise Web Applications with Cocoon and Spring DE1284: Creating Print on Demand solutions with Cocoon, FOP, and Lucene DE1272: Powering High-volume web sites with Lenya/Cocoon and mod_cache

190 Thank you! Questions?


Download ppt "Taming Cocoon ApacheCon Europe 2005 Gianugo Rabellino."

Similar presentations


Ads by Google