You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@cocoon.apache.org by "Morrison, John" <Jo...@uk.experian.com> on 2002/08/23 09:41:50 UTC
FW: Separation of logic/content (Was: XSP Best Practise Question)
I think Alan has some good points. Forwarded to cocoon-dev from -user.
J.
-----Original Message-----
From: Alan Hodgkinson [mailto:alan@softxs.ch]
Sent: Friday, 23 August 2002 9:45 am
To: cocoon-users@xml.apache.org
Subject: Separation of logic/content (Was: XSP Best Practise Question)
<warning>
This is a long post and contains no Cocoon sample code.
</warning>
Abstract
--------
I present a way of naming links form actions that allow
you to separate links and forms from the next page to
display. I then raise questions about processing web
application events, specifically how to do this within
the existing Cocoon pipeline mechanism and maintain a
separation between processing of the input from one page
from the generation and display of the next page. I then
say that Cocoon is great.
Introduction
------------
First Michael Edge wrote:
> I have a question regarding the use and purpose of XSP. I
> believe that XSP is an attempt to separate content/logic
> from presentation
Then Leigh Dodds wrote:
> I've been thinking along the same lines recently, and am
> still in two minds.
Join the club. Cocoon is just fine at separating presentation
from content and logic. The problem is the separation of the
content and logic.
I am relatively new to Cocoon and from what I've read of the
documentation and in the mail archive, it seems that Cocoon
is not yet ideal for web applications that have complex behavior
based on user input (e.g. the page flow changes based on the
data the user enters and the results of state changes in the
session and database/business-object layer). It's possible to
implement such applications with Cocoon, but it doesn't (yet)
seem to be Cocoon's strength.
The yet to be implemented flowmap mentioned in the cocoon-dev
mailing list may be the solution we are looking for. (Seach
for 'flowmap' in the cocoon-dev mailing list. The flowmap
is not yet fully defined, which means that now is the time
to provide your input).
It's About Control
------------------
Thinking in Model-View-Controller (MVC) terms, the problem
is how to separate the controller from the view/model. Note
that we don't need to worry too much about mixing up the
model and view, given Cocoon's flexible handling of XML
data via pipelines.
Mapping MVC to web applications is, in my mind, a priori,
a mess, due to the fact that the requests (events) the
web application receives must ultimately be encoded as links
and form actions in the HTML presented to the user. Thus
some mixing of view and control is required. In a sense,
we are trying to make the best of a bad situation.
Specifically, you have to embed links and form actions that
define the input events to the controller directly in
the in web pages. There are ways arund this, but before I
present a solution let's look at the types of input events
we need to consider.
Links in Content
----------------
A typical web application the links can be divided into
the following categories:
- Gotos: Links that simply take you to another part of
the application or web site. They typically make no
state change, except perhaps to note in a sessinon
variable that you are now on a different page. These
are typically simple links.
- Content Display: Links that display statically or
dynamically generated data, but cause no state change.
This includes search operations, and links/buttons that
display 'additional' information. Typically these are
links and buttons that include one or more key values
E.g. an id value or form data that identifies the
record(s) to display or present in the next page or
form.
- State changes: Links that cause a state change. This
includes business object and session state changes.
These can be quite complex operaions. Often these are
buttons associated with form data that the user enters.
How can you generate the embedded links and form actions
in web content without creating explicit dependencies
between the web pages (and also allow reuse of page
components via Cocoon's aggregation)? The answer is to
change the semantics of links and form actions.
Goto Considered Harmful, Come-From is Fine
------------------------------------------
Instead of having the link tell the controller where it
wants to go, which is the controller's responsibility,
it should merely tell the controller which button/link
it 'is' or, in other words, where it is 'coming from'.
For example, instead of a button having form action
named:
/cgi-bin/doUserUpdateSubmit.pl
which says what the web server should do, you would
have:
/userUpdateForm/changeName/submitButton
Which tells the controller exactly where the button was
pressed (and consequently what parameters it should
expect) and allows the controller the freedom do decide
where to go next. More importantly, the developer is
free to rearrange and reuse the pages and page components
without changing the any of the links or form actions.
All that is required is to maintain a mapping of the
events and states to their action routines (this might
be stored in something called, say, a flowmap :)
The whole point of this is to define a 'URI space' that
enables you to specify, independent of physical location
or file naming, all the application events that the
controller must respond to. In other words, all the
buttons and links that the web application contains.
Obviously you must also define the fields and parameters
associated with the buttons and links, but at least you
have turned all the links and form actions into events
and dissociated them from the application flow.
So What About Cocoon?
---------------------
So far this all theory. The practical problem is:
How do you do this in Cocoon?
<disclaimer>
Being a Cocoon, newbie, I quickly reach my limits and
look to others to supply helpful suggestions. That said,
here are some ideas.
</disclaimer>
In the JSP/Servlet world, an obvious answer is the single
servlet solution mentioned by Liegh, where you have one
servlet that implements all the control logic and dispatches
to JSP pages for display. In servlet based applications
you're free to write as many servlets as you want. In
practice, pretty much everybody only writes one, which acts
as a controller.
There's probably going to be a parallel in Cocoon development
world. Perhaps we'll all end up writing a single master
pipeline that calls 'internal-only' pipeline components
to do all the generation and display work.
How to implement the controller? Actions seem a reasonable
choice. As explained in the Cocoon documentation, you can
implement an action that sets sitemap parameter(s) that
enables you to delegate the to the appropriate view based
on the processing of the request parameters, session
variables and business objects. This would require having
the 'master pipeline' described above.
The Controller could be implemented as a generic class
implementing Action, which could read an XML config file
(called the flowmap or FSM-config). The config file would
contain, in some form, the matrix of applictaion states and
events and their mappings to the 'action pipelines'.
It might be possible to encode the controller configuration
directly in the pipeline portion of the sitemap, but I'm not
sure that you want to include all that 'application code',
(which is what this information really is, in the sitemap.
Pipelines Are So Cool That I Want Two of Them
---------------------------------------------
How can I separate the processing of page the form data
from the page I just left, from the generation and display
of the page I am going to present next?
Cocoon, with it's powerful pipelines, seduces you into
implementing your processing and display in a single pipeline
(which might call sub-pipelines, but the point is that it's
a single event chain). The problem is, and you see it
mentioned in the mailing lists, that once the pipeline is
started, and the SAX events are flying towards the user,
there's no turning back or possibility for switching to
another pipeline if you discover or decide you want to
display something else.
When responding to a request I'd like to use one pipeline
composed of XSP logicsheets to perform the event processing
and then be able to switch to another pipeline to generate
the next page. All this should be managed by my controller
which gets to pick the second pipeline based on the
processing results from the first.
Is this even possible in Cocoon? Are redirects an answer?
My reading of the mail archives leads me to belive that this
is probably not the correct solution. But perhaps there's
some other technique.
It is of course possible to implement all the page processing
in Java, in an action class, which chooses the next page,
but then I loose all the advantages of the logicsheets.
Is there some trick we can use so that 'we have it all'?
I eagerly await your feedback and suggestions.
Best wishes to you all,
Alan Hodgkinson
P.S. Cocoon is great!
---------------------
Why? Because it works and because we can determine its future
with our code, commentary, rants, etc. Imagine trying to do this
with a commercial product.
---------------------------------------------------------------------
Please check that your question has not already been answered in the
FAQ before posting. <http://xml.apache.org/cocoon/faq/index.html>
To unsubscribe, e-mail: <co...@xml.apache.org>
For additional commands, e-mail: <co...@xml.apache.org>
=======================================================================
Information in this email and any attachments are confidential, and may
not be copied or used by anyone other than the addressee, nor disclosed
to any third party without our permission. There is no intention to
create any legally binding contract or other commitment through the use
of this email.
Experian Limited (registration number 653331).
Registered office: Talbot House, Talbot Street, Nottingham NG1 5HF
---------------------------------------------------------------------
To unsubscribe, e-mail: cocoon-dev-unsubscribe@xml.apache.org
For additional commands, email: cocoon-dev-help@xml.apache.org
Re: FW: Separation of logic/content (Was: XSP Best Practise Question)
Posted by Christian Haul <ha...@dvs1.informatik.tu-darmstadt.de>.
On 23.Aug.2002 -- 08:41 AM, Morrison, John wrote:
> I think Alan has some good points. Forwarded to cocoon-dev from -user.
You should definitely have a look at the flow as present in 2.1-dev
thanks to Ovidiu and Christopher. It has still some problems, but it
is much like having this single servlet.
I'm currently over a deadline so I'll just throw some code at you that
might illustrate use. When finished, cleaned up, and documented I plan
to put the whole thing up, either in applications or somewhere else on
the net.
*WARNING* The following is ugly code and if you might be offended by
such work, don't look at it. *WARNING*
The following is JavaScript code invoked through the sitemap using
<map:resource name="flow">
<!-- flow script -->
<map:script src="flow.js"/>
</map:resource>
<map:resource name="function">
<!-- invoke a JavaScript flow function -->
<map:call function="{target}">
<map:parameter name="prefix" value="{vquadrat-def:base-url}/protected/admin/internal"/>
</map:call>
</map:resource>
in addition, the following is needed:
<map:match pattern="kont/*">
<!-- protected continuations -->
<map:continue with="{1}"/>
</map:match>
Documentation is currently very sparse, but this is (pre-)alpha
anyway. There is a samll but complete example in the 2.1-dev snapshots.
function login(uriPrefix){
var i;
var j;
var validation;
var validation2;
var msg;
var tmp;
var tmp2;
var destination;
var menuitem = "login";
prefix=uriPrefix.slice(uriPrefix.indexOf('/',1));
// save original destination from request-URI
destination = inputValue("URI", "");
log.debug("original destination is "+destination);
log.debug("original destination == 'login' "+(destination=="login"));
log.debug("original destination indexOf('protected/') "+destination.indexOf("protected/"));
if (destination == "login" || destination.indexOf("protected/") == -1) {
destination = "protected/welcome";
} else if (destination.lastIndexOf("/logout")==destination.length-"/logout".length) {
destination = "login";
}
log.debug("destination is "+destination);
i = 0;
j = 0;
msg = "";
do {
i++;
validation = null;
validation2 = null;
tmp = inputValue("vquadrat-constants","base-url")+"/internal/login";
tmp2 = inputValue("vquadrat-constants","base-url")+"/internal_new/login";
do {
// send login page
if (j==0) {
mySendPage(tmp2,{}, menuitem);
j++;
} else {
mySendPage(tmp,{}, menuitem);
}
validation = act("vq-validator","",{"validate-set":"login"});
log.debug("validation = "+(validation==null? "null" : validation));
} while (validation == null);
// check if account is blocked
validation2 = act("vq-dbquery","",{"table-set":"is-not-blocked"});
log.debug("account blocked? validation2 = "+(validation2==null? "null" : validation2));
if (validation2 == null) {
msg="The system could not log you in. Your account may have been blocked now for some minutes.";
validation = null;
} else {
msg="";
// check if password is ok
validation = act("vq-dbsel","",{"table-set":"login"});
log.debug("passwd ok? validation = "+(validation==null? "null" : validation));
if (validation == null) {
// login failed, block account
msg="The system could not log you in. Your account may have been blocked now for some minutes.";
validation2 = act("vq-dbquery","",{"table-set":"block-login"});
log.debug("lock! validation2 = "+(validation2==null? "null" : validation2));
} else {
// login OK, set session attribute / clear failcount
outputSet("vq-session","userdata", validation);
outputSet("vq-session","logged-in", "true");
outputCommit("vq-session");
validation = act("vq-dbquery","",{"table-set":"block-clear"});
log.debug("reset lock? validation = "+(validation==null? "null" : validation));
}
}
} while((i<5)&&(validation==null));
// send original destination
mySendPage(destination,{}, menuitem);
// done
}
Chris.
--
C h r i s t i a n H a u l
haul@informatik.tu-darmstadt.de
fingerprint: 99B0 1D9D 7919 644A 4837 7D73 FEF9 6856 335A 9E08
---------------------------------------------------------------------
To unsubscribe, e-mail: cocoon-dev-unsubscribe@xml.apache.org
For additional commands, email: cocoon-dev-help@xml.apache.org