You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@cocoon.apache.org by Grzegorz Kossakowski <gr...@tuffmail.com> on 2007/08/15 00:15:55 UTC

[RT] The big picture of Servlet Service Framework

Hi Cocooners,

I promised to give an overview on our Servlet Service Framework, its status and relation to the
Resource-Oriented Architecture (ROA) and RESTful design principles. My knowledge about REST comes
mainly from RESTful Web Services[1] by Leaonard Richardson and Sam Ruby. I'll refer and quote it 
extensively using RSW abbrevation.

Sorry for taking so long to write this mail but I had serious problems with my ISP so I was often 
offline. It's my first [RT] mail so I kindly ask you to be gentle when you appraise.

                                               - o -


   Servlet Service Fw keeps Virtual Sitemap/Pipeline Components promise
   --------------------------------------------------------------------

Virtual Sitemap (or better, Pipeline) Components has been talked about for very long time. At spring
of 2005 Daniel said[2] that it was very near to usable implementation in trunk. I don't remember
further course of events but current status of that implementation is that it is laying in
whiteboard for rather educational purposes. There is some code that could be probably reused for
other purposes.

Development of that implementation has been suspended because other implementation (framework)
provides very similar functionality to the VPCs in more standard-compliant and Cocoon-independent
way. The framework I'm talking about is SSF (Servlet Service Framework), of course. It keeps promise
of VPCs by somehow by "accident".

Main purpose of SSF existence is to provide convenient for servlets collaboration, reuse and
connectivity. You can easily mount any class implementing javax.servlet.http.HttpServlet interface
at any path you like by using this simple Spring configuration:

     <bean id="demo.servlet" class="demo.DemoServlet">
       <servlet:context mount-path="/demo"/>
     </bean>

As has been said earlier, servlet can be connected to another servlet:

     <bean id="demo.servlet" class="demo.DemoServlet">
       <servlet:context mount-path="/demo">
         <servlet:connections>
           <!-- "demo2" is local name identifying connection to the demo.OtherDemoServlet bean -->
	  <entry key="demo2" value-ref="demo.OtherDemoServlet"/>
         </servlet:connections>
       </servlet:context>
     </bean>

This way one servlet can reference resources from another servlet by using simple URIs:

   servlet:demo2:/file

This URI identifies 'file' resource of demo.OtherDemoServlet. It's possible to resolve such URIs
because SSF provides custom implementation of Excalibur's Source interface. After resolving the URI
you can fetch actual resource of course; it is performed using standard HTTP (and servlet) method:
HTTP GET. It's important that SSF does not introduce new interfaces or paradigms, it makes use
purely of HTTP and Servlet specification for resource maniupulation. I'll come back to this
characteristic of SSF.

Now you know what's main purpose for SSF but you may start to wonder how it relates to VPCs. The
whole idea concentrates around question: if servlet source can give access to the data produced by
another servlet why cannot it pass that another servlet incoming data that it can compute resource
of? In other words, why can't we pass some input for servlet when calling it? It was Daniel who
wondered[3] about this, first time. As result of the discussion proposal for Postable
source has been made[4] by Daniel.

The idea was quite simple: if we use HTTP GET to fetch data, what about using HTTP POST to sent some
input? If you take into account that, in Cocoon 2.2, sitemap of every block is a servlet and let
special pipeline components to POST the data you get what Daniel proposed and what is, in a fact,
VPCs implementation. Current implementation has few limitations:
   * SAX events are serialized and parsed again when making POST request to the servlet service
   * caching is not supported at any mean
   * environmental data (request, session, flowscript context aka bizData) of caller is not
available in the called service

If you want to have more detailed look on postable source implementation take a look at
COCOON-2046[5] an COCOON-2050[6]. To see postable source in action, take a look at
servlet-service-sample module[7].

What needs emphasis it the use of POST method and understanding of "service" word. When Postable
Source is used in servlet service pipeline components, the HTTP POST method is simply used to feed
called pipeline (or servlet, in general) with data it is going to operate and is going to produce a
result from.
Nothing less, nothing more.
In this case called servlet shares "service" that should be understood as "an *resource* identified
by URI that takes input data and produces output data usually _whithout_ side effects". That means,
this kind of service should never support methods like PUT or DELETE. You should consider such
service as pipeline fragment or VPC that uses POST method as low-level detail of carrying data.

What's more, such service is not even close to ROA because it is not stateless. RSW book makes
statelessness one of requirements for ROA and describes it that way:

     /Statelessness/ means that every HTTP request happens in complete isolation. When client makes
     an HTTP request, it includes all information necessary for the server to fulfil that request.
     The server never relies on information from previous requests. If that information was
     important, the client would have sent it again in this request.

Service calls that makes use of Cocoon's environment forwarding (not implemented at the time) are
not stateless because request does not contain all needed data. Moreover, environment forwarding is
usually required to make use of sessions or continuations that are in contrast to the statelessness.

The conclusion is that kind of services are rather tied acting as VPCs and legacy servlet
integration have nothing to do with ROA so also with REST design rules.

                                               - o -


   Approaching the ROA and REST
   ----------------------------

What if we could relinquish environment forwarding? We could get stateless service of course.
Quoting RSW again:

     -- Creating subordinate resource --
     In a RESTful design, POST is commonly used to create subordinate resources: resources that exist
     in relation to some other "parent" resource. (..) To create a weblog entry or a database record,
     you POST to the parent: the weblog or database table.
     (..)
     Why can't you just use PUT to create subordinate resources? Well, sometimes you can. (..) The
     difference between PUT and POST is this: the client uses PUT when it's in chage of deciding
     which URI the new resource should have. The client uses POST when the server is in charge of
     deciding which URI the new resource should have.

And another sub chapter:

     -- Overloaded POST: The not-so-uniform interface --
     (..)
     The one use of POST I haven't explained is the one you're probably most familiar with, because
     it's the one that drives almost all web applications: providing a block of data, such as the
     result of submitting a form, to a data-handling process.

     What's a "data-handling process"? That sounds pretty vague. And, indeed, just about anything can
     be a data-handling process. Using POST this way turns a resource into a tiny message processor
     that acts like an XML-RPC server. The resource accepts POST requests, examines the request, and
     decides to do... something. Then it decides to serve to the client... some data...

     I call this use of POST /overloaded POST/, by analogy to operator overloading in a programming
     language. It's overloaded because a single HTTP method is being used to signify any number of
     non-HTTP methods. (..)

     As a REST partisan I don't like this very much, but occasionally it's unavoidable.


All I want to say here is that our services in Cocoon, when stateless, are somewhere in between true
REST and use of overloaded POST. It's not true REST for obvious reason - our services do not create
subordinate resources at any means. And it does not use truly overloaded POST because our service is
not really general XML-RPC server, it acts as such somehow. Surely our services examine requests do
something (execute pipeline) and serve to the client the result of pipeline's execution.

Even authors of RSW book admit that overloaded POST is good choice from time to time. My own opinion 
is that it's perfectly valid to use overloaded POST to implemented our servlet services. What's 
more, if you do so only in this particular case (servlet service implementation) we still have a 
chance to have Resource-Oriented Architecture.

                                               - o -


   Attaining ROA nirvana with Cocoon
   -------------------------------------

This paragraph is going to describe my own view on achieving ROA and as consequence 
RESTful-compliant design. I'll try to describe relation of various components we already have to 
achieving ROA.

   -- Sitemap --
It's old but still powerful component in Cocoon. As long as we deal with URIs sitemap's matching 
mechanisms will be relevant. Take a look at quotation from RWS book, "When In Doubt, Make It a 
Resource" sub-chapter:
     (..)
     The larger point of this section is that when I say "anything can be a resource" I do mean
     /anything/. If there's a concept that's causing you design troubles, you can usually fit it into
     the ROA by exposing it as a new kind of resource. (..)

This indicates that as consequence of ROA one is going to have plenty of resources. Each resource 
has an URI that must be handled somehow. Here power of sitemap's matchers can really shine. The RWS 
book makes a lot of examples in Ruby and showed in Example 7-3 code of routes.rb file. I'll give you 
some snippet so you can get an idea of it's purpose:
   ActionController::Routing::Routes.draw do |map|
     base = '/v1'

     ## The first controller I define is the UsersController. The call to
     ## map.resources sets it up so that all HTTP request to /v1/users
     ## or /v1/users{username} are routed to the UsersController class.

     # /v1/users => UsersController
     map.resources :users, :path_prefix => base

     ## Now I'm going to define a number of controllers beneath the
     ## UsersController. They will respond to requests for URIs that start out
     ## with /v1/users/{username}, and then have some extra stuff.
     user_base = base + '/users/:username'

     # /v1/users/{username}/bookmarks => BookmarksController
     map.resources :bookmarks, :path_prefix => user_base

     [..]
   end

You probably guessed it, routes.rb file acts as simple dispatcher that dispatches requests to the 
controller. Quite the same could be achieved with our sitemap engine:

   <map:sitemap>
     <map:pipeline>

       <map:match pattern="/v1/users/*/bookmarks/*">
         <map:call function="bookmarksController_handle{$cocoon/request/method}">
           <map:parameter name="username" value="{1}"/>
           <map:parameter name="bookmark" value="{2}"/>
         </map:call>
       </map:match>

       <map:match pattern="/v1/users/*">
         <map:call function="usersController_handle{$cocoon/request/method}">
           <map:parameter name="username" value="{1}"/>
         </map:call>
       </map:match>

     </map:pipeline>
   </map:sitemap>

This code could be done much compact by coming up with conventions but it's topic for another 
discussion, really.

   -- Servlet Service Framework --
It's new, hot part of Cocoon and really ROA-enabled one. I think one of the most important features 
of SSF from both ROA and implementation POVS is ability to mount new servlets (blocks) at certain 
URI and ability to extend[8] URI space of one servlet by another one.

SSF enable you to easily map structure of your app (blocks) to URI design and handle any number of 
resources very easily. If one block becomes overloaded by number of resource it has to handle you 
can always break it into two without any pain at all.

When extending one block by another, you extend URI space so there is no magic behind the scene 
here, either. You can go with such advanced functionality like extension of existing blocks and stay 
100% ROA-compliant. Actually, current architecture of SSF enforces on you to some extent being 
ROA-compliant.

I think that servlet: source concentrates all the power of SSF design. So what's servlet: source? It is:
   * scheme that it lets you to address resources from other servlets (it's actually meta-address, 
more below)
   * normal Excalibur source that lets you to ask other servlets for resource's data
   * very convenient links factory that is aware of servlet inheritance

First and third points are tightly coupled. Servlet URIs are, in a fact, meta-URIs or better 
relative URIs. If you write such URI:
servlet:mapsBlock:/map1/town2

It only makes sense only if you now to which servlet configuration it belongs to because it is going 
to be resolved against servlet's connections map and servlet inheritance will have to be taken into 
consideration. Servlet URIs are relative to particular configuration.

RWS book mentions connectedness as one of the most important indicators of ROA design. If we want to 
make a web service we need to fulfil "web" part requirements. Web is about hyper links connecting 
resources and we have to create a lot of links. Here servlet: source power shines because you use 
exactly the same scheme for accessing the resource on the server side (in sitemaps) and you put them 
into templates of the content served to the client. And you don't have to bother when another 
servlet extends your servlet, servlet: source *will* respect that for free.

   -- Flowscript --
When approaching ROA design we need to throw out continuations of course. So what's the use of 
flowscript, then?

It's my very own opinion but I think that our controllers should be sitemap(as 
dispatcher)+script(containing actual controller's code). I think that most of us would agree that 
dynamic languages have some features really useful for fast prototyping and glueing code.

I take role of flowscript and pipelines (below) really briefly because it's quite far from big 
picture of Servlet Service Framework. :-)

   -- Pipelines --
Our pipelines already proved to be very powerful in publishing framework. If we think about Cocoon 
as RESTful framework we can be sure that our pipelines will still be doing great job when we want to 
serve resource's representation that would be usually custom XML or XHTML.

                                               - o -

Ok, that's all for now. Thanks for reading.

[1] ISBN: 0-596-52926-0 http://www.oreilly.com/catalog/9780596529260/
[2] http://article.gmane.org/gmane.text.xml.cocoon.devel/49148
[3] http://article.gmane.org/gmane.text.xml.cocoon.devel/67480
[4] http://article.gmane.org/gmane.text.xml.cocoon.devel/67487
[5] https://issues.apache.org/jira/browse/COCOON-2046
[6] https://issues.apache.org/jira/browse/COCOON-2050
[7]
http://svn.apache.org/repos/asf/cocoon/trunk/core/cocoon-servlet-service/cocoon-servlet-service-sample/
[8] https://issues.apache.org/jira/browse/COCOON-2038

-- 
Grzegorz Kossakowski
http://reflectingonthevicissitudes.wordpress.com/

Re: [RT] The big picture of Servlet Service Framework

Posted by Grzegorz Kossakowski <gk...@apache.org>.
Dev at weitling pisze:
> Sounds cool, but doesn't this result in a scenario like this?:
> - browser calls resource A
> - resource A runs through a pipeline calling resource B
> - resource A is a SAX-pipeline, serializes SAX-events to POST-parameters
> for calling B

You are not limited to POSTing XML data. You can POST anything you like if you put service calling 
at the beginning of the A's pipeline.

> - resource B deserializes parameters, feeds its own pipeline with
> SAX-events, serializes results to HTTP-like result, feeds it back to
> resource B
> 
> Seems we have a loss in performance and increase in memory needs.

If you take a look at COCOON-2046 issue you will notice that comment:

   First implementation is going to be very naive and will not support caching nor SAX events
   forwarding (XML will be serialized/deserialized).

What's more, you will notice that it has subtask (COCOON-2050) with summary "Basic implementation of 
postable source".

That indicates the current implementation is first step to achieve all goals like environment 
forwarding and avoidance of xml serialization/parsing.

>> This code could be done much compact by coming up with conventions but
>> it's topic for another discussion, really.
> 
> I'm not sure if I fully catch on your example. Can you explain it a
> little bit more (as your eMail was addresses to the users list I bet I'm
> not the only one) ?
> What about handling the matching of non-URIs e.g. headers?
> I'm doubtful about conventions. IMO they should be only that -
> conventions - and not mandatory. For example a URL visible from external
> clients should not always represent the internal structure.

Conventions are intended to help developer, not limit her. In most scenarios, if developing truly 
RESTful application you are going to have quite simple correspondence between exposed resources 
(URIs) and your beans or even database structure. That's the case where convention can really help.

Nevertheless the point is to write less code and do more but if you really need to handle something 
unusual you are welcome to write more code (e.g. custom sitemap matcher implementation, or sitemap 
snippet) to handle that specific case.

> Please explain how you want to replace continuations and flowscript. One
> of the reasons why I prefer Cocoon are continuations! The extensive use
> of flowscript spread on myriads of files isn't great, though, but for
> controlling a flow (!) with reentrance without having to think about
> restoring variables is just great.
> Or do you want to move flowscript just into the sitemap?

No, no. I really want to get rid of sessions, continuations are variable restoring. So where to move 
flow control? The answer is simple: to the rich client.

I forgot to say at the very beginning of my e-mail that RESTful design makes sense only if on the 
other end is rich client. In this context 'rich' means the one that can fully take advantage of HTTP 
protocol. It means that it must be able to make DELETE and PUT calls apart from casual GET and POST. 
Most importantly, it means that client is able to handle it's state and make sensible request to the 
server basing on client's state.

If you ask me about examples that I have in mind I can give you two:
   a) Ajax applications. They are capable enough to handle their own state and should be able to 
deal with RESTful design. I have not evaluated this option extensively but there are plenty of 
resources talking about REST and Ajax on the Internet.
   b) JavaFX. This technology is really new and it is still hard to find answers to all questions. 
You can take a look at homepage of OpenJXF[1] to have an idea. Nevertheless, I think there is a 
large Java's community interest in success of this technology and I believe we will be able to 
easily write rich client applications using JavaFX. As soon as it will be possible to embed JavaFX 
application into web page I'm going to evaluate how to integrate it with Cocoon (by giving an 
examples). A long term goal would be to make implementation of CForms stateless and RESTful and 
develop rich client for handling general CForms so you can get advanced widgets without hacking HTML 
and numerous browsers.

You may think that this e-mail talks about very distant future. It may be true, but it's the main 
purpose of [RT] e-mails to envision the future.

> P.S.: What ist [RT] ? And it would increase readibility if you introduce
> abbreviations the first you use them (sorry, just my egoistic view ;-)

Cocoon has a long tradition of [RT] e-mails that stands for Random Thought. Since my e-mail was 
addressed to devs are already familiar with this abbrevation and don't need introduction.

When inviting users willing to find out more about Cocoon's development I actually explained what RT 
means. ;-)

[1] https://openjfx.dev.java.net/

-- 
Grzegorz Kossakowski
http://reflectingonthevicissitudes.wordpress.com/
*** My Internet Service Provider breaks my internet connection                ***
*** incessantly so I'll not be able to respond to e-mails                     ***
*** regularly and my work will be somehow irregular.                          ***
*** I'm already trying to switch ISP but it will take handful amount of time. ***

Re: [RT] The big picture of Servlet Service Framework

Posted by Dev at weitling <de...@weitling.net>.
Hi Grek,

you asked us to give our two cents so after a day of reading your long,
long text I'll try to ;-)
I'll surely have to re-read it but here are some thoughts:

> I promised to give an overview on our Servlet Service Framework, its
> status and relation to the
> Resource-Oriented Architecture (ROA) and RESTful design principles. 
> It's my first [RT] mail so I kindly ask you to be gentle when you
> appraise.
>
>   Servlet Service Fw keeps Virtual Sitemap/Pipeline Components promise
>   --------------------------------------------------------------------
>
> Current implementation has few limitations:
>   * SAX events are serialized and parsed again when making POST
> request to the servlet service
>   * caching is not supported at any mean
>   * environmental data (request, session, flowscript context aka
> bizData) of caller is not
> available in the called service

Sounds cool, but doesn't this result in a scenario like this?:
- browser calls resource A
- resource A runs through a pipeline calling resource B
- resource A is a SAX-pipeline, serializes SAX-events to POST-parameters
for calling B
- resource B deserializes parameters, feeds its own pipeline with
SAX-events, serializes results to HTTP-like result, feeds it back to
resource B

Seems we have a loss in performance and increase in memory needs.

>   Attaining ROA nirvana with Cocoon
>   -------------------------------------
>
>   -- Sitemap --
> It's old but still powerful component in Cocoon. As long as we deal
> with URIs sitemap's matching mechanisms will be relevant. Take a look
> at quotation from RWS book, "When In Doubt, Make It a Resource"
> sub-chapter:
> You probably guessed it, routes.rb file acts as simple dispatcher that
> dispatches requests to the controller. Quite the same could be
> achieved with our sitemap engine:
>
>   <map:sitemap>
>     <map:pipeline>
>
>       <map:match pattern="/v1/users/*/bookmarks/*">
>         <map:call
> function="bookmarksController_handle{$cocoon/request/method}">
>           <map:parameter name="username" value="{1}"/>
>           <map:parameter name="bookmark" value="{2}"/>
>         </map:call>
>       </map:match>
>
>       <map:match pattern="/v1/users/*">
>         <map:call
> function="usersController_handle{$cocoon/request/method}">
>           <map:parameter name="username" value="{1}"/>
>         </map:call>
>       </map:match>
>
>     </map:pipeline>
>   </map:sitemap>
>
> This code could be done much compact by coming up with conventions but
> it's topic for another discussion, really.

I'm not sure if I fully catch on your example. Can you explain it a
little bit more (as your eMail was addresses to the users list I bet I'm
not the only one) ?
What about handling the matching of non-URIs e.g. headers?
I'm doubtful about conventions. IMO they should be only that -
conventions - and not mandatory. For example a URL visible from external
clients should not always represent the internal structure.

>   -- Flowscript --
> When approaching ROA design we need to throw out continuations of
> course. So what's the use of flowscript, then?
>
> It's my very own opinion but I think that our controllers should be
> sitemap(as dispatcher)+script(containing actual controller's code). I
> think that most of us would agree that dynamic languages have some
> features really useful for fast prototyping and glueing code.
>
> I take role of flowscript and pipelines (below) really briefly because
> it's quite far from big picture of Servlet Service Framework. :-)

Please explain how you want to replace continuations and flowscript. One
of the reasons why I prefer Cocoon are continuations! The extensive use
of flowscript spread on myriads of files isn't great, though, but for
controlling a flow (!) with reentrance without having to think about
restoring variables is just great.
Or do you want to move flowscript just into the sitemap?

Bye,
Florian


P.S.: What ist [RT] ? And it would increase readibility if you introduce
abbreviations the first you use them (sorry, just my egoistic view ;-)