0

I have a JSF 2.0 (and Richfaces 4.0) application and I'd like to do something that seems simple.

I have a landing page (/index.xhtml) that is the 'welcome page' that is comes up when someone types "www.xxx.com" with xxx as my domain.

  1. I want to have an alternate landing page that will be the target of an ad that we're running. The way I was going to approach this since I'm going to highly customize this content is just have a new page: www.xxx.com/intro.xhtml. So far so good. My index page index.xhtml (and its copy intro.xhtml) has a bunch of linked public pages: "how it works", "sign up", etc... pretty typical stuff.
  2. The problem is how to I preserve or track the fact that the targeted users entered my site via the intro.xhtml when the go to "how it works" and then go back to the home page?

The use case that will be a problem is:

  • user comes in via the ad and they're at intro.xhtml with the customized content.
  • They go to a shared home page ("how it works").
  • then they click home (or the site icon) to go back to home. As of now they go back to the welcome page (index.xhtml) which will be confusing to them.

All I can think of is:

  • I could make a 'deep copy' of all of my other public pages (e.g. how_it_works copied to how_it_works_intro) and then have the _intro page link back to the intro.xhtml page when someone selections home from that, but that seems really dumb.
  • do some post processing of the request in a servlet filter (say set session variable when the user initially hits intro.xhtml) and use this fact to route them back to intro.xhtml when they click home. But this seems like a bad idea because I don't want to start a session until they login. It also gets away from keeping all of your page flow in the faces-config.xml which I've done so far for the entire app.
  • A session is always started regardless of whether someone logs in or not. – Bill Rosmus Aug 12 '12 at 18:21
  • 2
    @BillR: *Always*? You're wrong. It would only be created once a view or session scoped managed bean has been constructed for the first time and/or once a page with a ``has been requested for the first time (while the state saving method is set to server). – BalusC Aug 12 '12 at 23:45
  • I believe the spec says that a session is created any time server state needs to tracked. So anything beyond the most trivial will require a session. Essentially for pretty much anything with JSF a session is needed. If a person who is doing something that trivial they won't be using JSF. – Bill Rosmus Aug 13 '12 at 15:48
  • @BillR: So all of your trivial pages contain a ``? Well, then it's no surprise that the session would always be created :) That's fine, but don't overgeneralize your case with all others. The average JSF webapp may also contains a bunch of "static pages" wherein no `` is involved at all. Mostly as the "public" part which represents the public entry of the webapp. No session would then need to be created. – BalusC Aug 13 '12 at 16:53
  • I think you both may be right. I have some purely static xhtml page (contact us) but I think BillR is right in that I created common widgets (e.g. a questions / comments little form) that does reference a session level bean. To be fair, even my home page references a session bean - which could be thought of as bad practice. I do this because once a user is logged in, if they get back to the public pages (via the back button or entering in a URL) I let them get back to the protected pages without logging in again. So in my case, Bill is right. – paul.da.programmer Aug 13 '12 at 21:11
  • @BalusC to clarify I added an answer below. – Bill Rosmus Aug 14 '12 at 04:27
  • Paul: in your case, the session is created because you're using a session scoped bean. @Bill: in your case, the session is created because you explicitly did it yourself. – BalusC Aug 14 '12 at 11:09
  • Still in a request bean not session nor form. So the answer is somewhere in the middle. But I see that I requested it. Anyway, now that that is over I'll delete my answer to clean this post up for Paul. Sorry Paul. – Bill Rosmus Aug 14 '12 at 16:29

3 Answers3

0

Usually this is achieved by adding some parameters to the query string. For example:

From you intro.xhtml, append these parameters to the "How it works page" like this:

<h:link value="How it works" outcome="howitworks" includeViewParams="true">
   <f:param name="landingvia" value="intro"/>
</h:link>

Then in your howitworks.xhtml render the home page link like this:

<h:link value="Home" outcome="intro" rendered="#{param.landingvia == 'intro'}" />
<h:link value="Home" outcome="index" rendered="#{param.landingvia == 'index'}" />
Ravi Kadaboina
  • 8,494
  • 3
  • 30
  • 42
  • I will definitely try this tonight - I haven't used get parameters in JSF yet (used them many times in JSP and servlets). I'll read up and post a back. Thanks! – paul.da.programmer Aug 13 '12 at 21:14
  • ok, tried this last night (for a number of hours) and it turns out that this is either not a good solution for any non-trivial application OR I'm not doing something right. Either one may be correct at this point. I'll expand on the issue below. – paul.da.programmer Aug 14 '12 at 14:16
0

In trying to implement the solution as proposed by Ravi, there were the following issues:

  1. My application heavily leverages JSF templating (via ui:composition) so the answer below wont directly work. But the way around that is to use the ui:param tag which did work. So I added the following to the index and intro pages:

    <!-- this is in my intro.xhtml page -->
    <ui:composition template="templates/header-public.xhtml">
    <ui:param name="landingvia" value="intro"/>
    

with the similar line in the index.xhtml page

    <ui:param name="landingvia" value="index"/>
  1. Then in the header-public.xhtml page I needed to change the links as per Ravi (doing this from memory) but you get the idea. Note that I needed to use "landingvia" instead of "param.landingvia" probably because of the tempalting.

    <h:commandLink value="Home" outcome="/intro" rendered="#{landingvia == 'intro'}" ><f:param name="landingvia" value="intro" /> </h:commandLink
    <h:commandLink value="Home" outcome="/index" rendered="#{landingvia == 'index'}" ><f:param name="landingvia" value="index" /> </h:commandLink
    <h:commandLink value="About" outcome="/about" rendered="#{landingvia == 'intro'}" ><f:param name="landingvia" value="intro" /> </h:commandLink
    <h:commandLink value="About" outcome="/about" rendered="#{landingvia == 'index'}" ><f:param name="landingvia" value="index" /> </h:commandLink
    

    ... I would need to do the same duplication for all of the links (contactus, faq, etc...) on the header AND the footer (which has other links) included in the template and for image links (logos etc...) and for links from say faq to termsAndConditions.xhtml ... Not a good solution.

  2. If I don't add the f:param tag to all of the commandLinks above, the state is 'lost' which makes sense. When I go from intro to About, how would the About page track the landing page without the f:param tag?

  3. The make matter worse, all links from any page to any page needs to follow this pattern. So this is not a good solution, unless I'm doing something very wrong.

  4. As a final issue, I found that even if all of the links were duplicated as above, the solution still wont work because when there are immediate forms (these forms send a form.submit() back to themselves) the state is lost anyway.

At this point I'm going to just manage the state on the server side. So I can either use my user session bean or set a session cookie.

  • I'm creating a Session level "user" object on my home page anyway. So I can use that by just calling from intro.xhtml

    #{userBean.setLandingPage('intro')
    
  • Or set a cookie from either page.

Once I put a value that is either ("index" or "intro") into the session (via cookie or session bean) I can interrogate all URLs in a ServletFilter and if its destination is "/index" or "/" or "/index.xhtml" then I'll use the session variable. If it contains the value "intro" I'll send the user to /intro.xhtml instead.

I don't know how else to do it without a massive amount of work. But the solution above works well with no change to any of the links and it has the added benefit of being extensible to as many future landing pages as I need. Let me know your thoughts and Ravi please let me know if I'm not getting your solution.

0

Ok guys, I <think> I completely nailed it and came up with an elegant solution. It may be obvious to those whom are experts in JSF but I'm definitely not (I'm more a backend Java EE programmer)

Here's exactly what I did.

  1. added a landingPage attribute to my userBean (my user session bean). As stated above I don't care that I'm starting a session on my home page(s) because I'm doing it anyway.
  2. in all my landing pages I add the follwing with the appropriate URI that points back to the page itself. In this case /index resolves to the index page itself. in index.xhtml added:

     #{userBean.setLandingPage('/index')}
    

in intro.xhtml added:

     #{userBean.setLandingPage('/intro')}
  1. Then all I needed to do is adjust all references in my JSF pages to reference the session value. So in my header.xhtml I change all

    <h:commandLink class="active" action="/index">home</h:commandLink>
    

    to

    <h:commandLink class="active" action="#{userBean.getLandingPage}">home</h:commandLink>
    
  2. Only the home page references need to change, none of the other links need to change

  3. It will also be REAL easy to add additional landing pages and the stateful behavior.

I'm real happy with the solution. Thanks everyone!

Arjan Tijms
  • 37,782
  • 12
  • 108
  • 140
  • Looks good Paul, you also might want to use instead of for bookmarkability. See also [when-should-i-use-houtputlink-instead-of-hcommandlink](http://stackoverflow.com/questions/4317684/when-should-i-use-houtputlink-instead-of-hcommandlink) – Ravi Kadaboina Aug 15 '12 at 14:46
  • Thanks Ravi - I'll definitely look into the h:link vs h:commandLink issue. I was actually looking into going for the PrettyFaces solution (http://ocpsoft.org/prettyfaces/) which I'm not sure obviates the need to change the h:commandLink tags. – paul.da.programmer Aug 15 '12 at 20:29