[opencms-dev] RE: Sharing state across included JSPs

Jonathan Woods jonathan.woods at scintillance.com
Tue Apr 24 07:05:45 CEST 2007


Hi.  Hope you don't mind me posting your question back to the list.

I don't know the details of your <cms:includes> and so on, but maybe you can
work out something from what I'm about to write.  Warning: I don't like the
syntax or loss of control caused by taglibs, so I tend to use real Java -
you may not like this style!  And I've over-complicated things to show you
the most general way of sharing state among JSPs.

It sounds like you have two problems.  The first is getting the right uri
prefix (/opencms/opencms); and the second is getting the value of the uri
originally requested by the user, and making sure that this value really
_is_ what they requested, not what the OpenCms dispatching/including
mechanism thinks (this being the cause of your footer problem).

1.  Pretty much the first steps towards gaining complete control over the
OpenCms JSP environment involve getting access to all the useful OpenCms
objects modelling request state.  You can use the following code near the
beginning of every JSP:

final CmsJspActionElement cmsJspActionElement = new CmsJspActionElement();
cmsJspActionElement.init(pageContext, request, response);
final CmsObject cmsObject = cmsJspActionElement.getCmsObject();
final CmsRequestContext requestContext = cmsObject.getRequestContext();

2.  Armed with all that, you can always derive the right uri for links like
this:

String fullLink =
cmsJspActionElement.link(theSiteRelativeVFSPathToWhichYouWantToLink);

This is of course just like using <cms:link>, which calls
CmsJspActionElement.link under the convoluted JSP hood - the difference is
that you've put the value into a Java variable and you can do anything you
like with it without being constrained by taglib nightmares like <c:set> and
so on.

3.  I believe the originally requested uri is always available from
CmsRequestContext.getUri().  But I'll ignore that just to show how I pass
state around between JSPs.

3a.  First, define your own class which you're going to use to share state
between included JSPs.  This can hold anything you like, though in theory
any instance fields used for value transfer should be Serializable.  So
something like this:

public class RequestState {
	private String originallyRequestedUri;
	
	public RequestState() {
		super();
	}
	
	public String getOriginallyRequestedUri() {
		return this.originallyRequestedUri;
	}
}

3b.	Maybe I need to explain how my JSPs interact.  The top level JSPs
are those used to render requested resources, so they are set as the value
of the relevant property expected by OpenCms for this purpose: the
template-elements property for XML content and the template property for
xmlpage content.  They all have the following structure:

	<cms:include file="path to header JSP"/>

	// The code for _this_ JSP, which may also include sub-JSPs
	// (e.g. for displaying well defined areas of a page.  And finally:

	<cms:include file="path to footer JSP"/>

3c.  Before much else in the process of any JSP's execution, I set up the
shared state...

	final RequestState requestState = new RequestState();

	// Now follows a call into OpenCms API using a variable we defined
in 2 above:
	requestState.setOriginallyRequestedUri(requestContext.getUri());

	// Could install into requestState any other state you want to share
here - any kind of Object, preferably Serializable.

3d.	... and then ensure that it _can_ be shared:

	requestContext.setAttribute("TheStringKeyForMySharedState",
requestState);

Here you are setting an attribute on an OpenCms object, an instance of
CmsRequestContext.  That's the best place to share state for a single
request.  The key can be anything you like, but you'll need to use the same
value in 3e below.  And of course for the attribute value, we could just
have used originallyRequestedUri if that's all you want to share - but it
never is, and without encapsulating shared state in a class like
RequestState you end up with a mish-mash of String attribute-value nonsense
which is hard to debug.

3e.	Now, in subsequently invoked JSPs - e.g. the footer JSP, in my
example code above - you can retrieve the shared RequestState instance like
this:

	// Same initial code as before, i.e. to get an instance of
CmsRequestContext.  Then:
	final RequestState requestState = (RequestState)
requestContext.getAttribute("TheStringKeyForMySharedState");

3f.	Now you can use e.g.

	<p>Here in my footer, click <a href="<%=
cmsJspActionElement.link("/siteutilities/print.jsp") + "?uri=" +
requestState.getOriginallyRequestedUri()) %>">here</a> for a printed
version.</p>

I don't know if that's how you are communicating to your 'print page'
functionality, but that's the most obvious way I can think of.

I hope this hasn't made things still more confusing!

Jon

-----Original Message-----
From: roth.lisa at jimmy.harvard.edu [mailto:roth.lisa at jimmy.harvard.edu] 
Sent: 24 April 2007 01:14
To: jonathan.woods at scintillance.com
Subject: AW: Sharing state across included JSPs

Hi there,

Could you share the solve with me? I am having a heck of a time passing the
current URI to a new window to create a print-only version. If I put the
link to the new window IN the body, it gives me an incomplete address
(without the server/opencms/opencms), and if I put it in the footer, it
tries to show me the FOOTER in a new window, still without the
opencms/opencms

Thanks a lot in advance!!

Jonathan Woods wrote:
> 
> For what it's worth, problem solved - I was making a dumb mistake.  
> You can set request attributes (as opposed to parameters) to any kind 
> of Object you like, and retrieve them in subsequently executed page 
> elements.  I'd tried to retrieve mine before the <cms:include> 
> invocation, but now that I've put things in the right order it all 
> works fine.
>  
> Jon
> 
>   _____
> 
> From: opencms-dev-bounces at opencms.org
> [mailto:opencms-dev-bounces at opencms.org] On Behalf Of Jonathan Woods
> Sent: 28 February 2006 20:09
> To: 'The OpenCms mailing list'
> Subject: [opencms-dev] Sharing state across included JSPs
> 
> 
> I have a JSP template which uses <cms:include> to include a couple of 
> other JSP page elements (header and footer, predictably enough).  I 
> create an object or two in the header which I need to use in the page 
> body and in the footer, but at the moment I'm struggling to see how I 
> can share the object
> reference:
>  
> 1.  Putting it into the page context, either via Java
> (pageContext.setAttribute()) or via <jsp:useBean>, doesn't seem to 
> work - I guess this is because the 'include' is dynamic and we're 
> dealing with different Java scopes.
>  
> 2. Same with the request context, again because the include is dynamic.
> OpenCms documentation suggests that you can set request parameters 
> before executing the include, but from the taglib only String setting 
> is possible
> -
> and I want to share a reference to something other than a String.
>  
> 3.  Putting it into session context is (i) a pity, because otherwise I 
> don't need to set up sessions and maintain session state, and (ii) not 
> really appropriate, because in theory the same client could make two 
> requests so quickly that two JSP-serving threads would hit the same 
> session state.  I realise there are ways round (ii), but I'd rather 
> not go there if there's an easier solution.
>  
> Any ideas welcomed.  I would really love to get on with some coding 
> and stop having to wrestle with the execution environment like this!
>  
> Jon
>  
> 
> 
> _______________________________________________
> This mail is sent to you from the opencms-dev mailing list To change 
> your list options, or to unsubscribe from the list, please visit 
> http://lists.opencms.org/mailman/listinfo/opencms-dev
> 
Quoted from: 
http://www.nabble.com/Sharing-state-across-included-JSPs-tf1201419.html#a318
3405







More information about the opencms-dev mailing list