loading table of contents...

6.3.13. Managing End User Interactions

Requirements

For a truly engaging experience website visitors need to be able to interact with your website. Interactions can reach from basic ways to search content, register and give feedback to enabling user-to-user communication and facilitating business processes such as product registration and customer self care.

End user interactions should be configurable in the editorial interface by non-technical users in the editorial interface of the system. It should, for example, be possible to place interaction components such as Login and Search buttons on pages just like any other content, configure layout and business rules etc.

Solution

For the Blueprint website, the term "action" denotes a functionality that enables users to interact with the website.

Examples:

  • Search: The "search" action lets user to enter a query into a form field. After processing the search, a search result is displayed to the user.

  • Login: This action can be used by users to login to the website by adding user name and password credentials. A successful login changes the state web application's state for the user and offers him additional actions such as editing his user profile.

From an editor's perspective, all actions are represented by content objects of type CMAction. This enables an editor to add an action content to a page, for example by inserting it to the navigation linklist property. When rendering the page, this action object is rendered by a certain template that (for example) renders a search form. The submitted form data (the query, for instance) is received by a handler that does some processing (passing the query to the search engine, for instance) and that provides a model containing the search action result.

This section demonstrates the steps necessary to add new actions to CoreMedia Blueprint. It also helps to understand the currently available actions.

Standard Actions

As stated above, all actions are represented as CMAction contents in the repository. These contents can be used as placeholders in terms of the "substitution" mechanism described in the [ CAE Developer Manual]. An example for adding a new action: Consider an action where users can submit their email addresses in order to receive a newsletter.

  1. Create a bean that represents the subscription form and add an adequate template.

            public class SubscriptionForm {
      public String email;
    
      public void setEmail(String email) {
        this.email = email;
      }
    
      public String getEmail() {
        return email;
      }
    }
          

    SubscriptionForm.asTeaser.jsp

            <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
    <%--@elvariable id="self" type="com.mycompany.SubscriptionForm "--%>
    <%--@elvariable id="subscriptionForm" type="com.mycompany.SubscriptionForm "--%>
    <%--@elvariable id="cmpage" type="com.coremedia.blueprint.common.contentbeans.Page"--%>
    <cm:link target="${cmpage.linkable}" var="redirectUri"/>
    <cm:link target="${self}" var="subscriptionUri">
      <cm:param name="return" value="${redirectUri}"/>
    </cm:link>
    <form:form id="subscriptionForm" modelAttribute="subscriptionForm"
               action="${subscriptionUri}" method="post">
      <form:input path="email"/>
      <input type="submit"/>
    </form:form>
          
  2. Add a handler that is able to process the subscription as well as a link scheme that builds links pointing to the handler.

            @Link
    @RequestMapping
    public class SubscriptionHandler {
    
      @RequestMapping(value="/subscribe", method=RequestMethod.POST)
      public ModelAndView handleSubscription(@RequestParam(value="return", required=true) String redirectUri,
                                             @ModelAttribute("subscriptionForm") SubscriptionForm form,
                                             HttpServletRequest request, HttpServletResponse response)
              throws IOException {
        doSubscribe(request.getSession(), form.getEmail());
        response.sendRedirect(redirectUri);
        return null;
      }
    
      @Link(type=SubscriptionForm.class, parameter="return", uri="/subscribe")
      public UriComponents createSubscriptionLink(UriComponentsBuilder uri, Map<String,Object> parameters) {
        return uri.queryParam("return", (String) parameters.get("return")).build();
      }
    
      ...
    }
          

    Don't forget to register this class as a bean in the Spring application context.

  3. Define an action substitution.

            public class SubscriptionHandler {
      ...
      @Substitution("com.coremedia.subscription", modelAttribute="subscriptionForm")
      public SubscriptionForm createSubscriptionSubstitution(CMAction original, HttpServletRequest request) {
        return new SubscriptionForm();
      }
      ...
    }
          

    Notes

    • The parameters original as well as request are optional and might be omitted here. But in a more proper implementation it might be useful to have access to the original bean and the current request.

    • The optional modelAttribute causes the substitution to be become available as a request attribute subscriptionForm. This is useful when using dealing with the Spring form tag library (see above).

  4. Create a newsletter action content

    • Create a content of type CMAction

    • Set the id property to value com.coremedia.subscription

    • Insert this content to a page's teaser link list.

Here is what happens when opening the page by sending an HTTP request:

  1. The request will be accepted by the PageHandler that builds a ModelAndView containing the Page model. This model's tree of content beans contains the new CMAction instance.

  2. The model will be rendered by initially invoking Page.jsp for the Page bean.

  3. When the CMAction is going to be rendered in the teaser list, the template CMAction.asTeaser.jsp is invoked. This template substitutes the CMAction bean by invoking the cm:substitute function while using the ID com.coremedia.subscription.

  4. The substitution framework invokes the method #createSubscriptionSubstitution after checking whether SubstitutionRegistry#register has been invoked by any handler for his ID (which hasn't happened here). As the result, the substitutions result is a bean of type SubscriptionForm.

  5. The above mentioned template CMAction.asTeaser.jsp therefore delegates to SubscriptionForm.asTeaser.jsp then.

  6. While rendering SubscriptionForm.asTeaser.jsp, a link pointing to this form bean is going to be built. The method #createSubscriptionLink is chosen as a link scheme so that the link points to the handler method #handleSubscription.

  7. After the user has received the rendered page, he might enter his email address and press the submit button.

  8. This new (POST) request is accepted by the mentioned handler method #handleSubscription that performs the subscription and redirects the original page then so that the first step of this flow is repeated.

Of course, a more proper implementation could mark the subscription state (subscribed or not) in a session/cookie and would return an UnsubscribeForm from #createSubscriptionSubstitution depending on this state.

Webflow Actions

Spring Webflow (http://www.springsource.org/spring-web-flow) is a framework for building complex form based applications consisting of multiple steps. Webflow based actions can be integrated into Blueprint as well. This section describes the steps of how to integrate this kind of actions.

In CoreMedia Blueprint the PageActionHandler takes care of generally handling Webflow actions. The flow's out coming model is automatically wrapped into a bean WebflowActionState. A special aspect of this bean is that it implements HasCustomType and therefore is able to control the lookup of the of the matching template.

  1. Place your flow definition file somewhere below a package named webflow somewhere in the classpath. The name of the flow definition file should be <action_id>.xml. Example: For an action com.mycompany.MyFlowAction you might create a file com.mycompany.MyFlowAction.xml that can be placed below a package com.coremedia.blueprint.mycompany.webflow.

  2. For every flow view (such as "success" or "failure") create a JSP template. The template name needs to match the action id. Example: The action com.mycompany.MyFlowAction requires templates to be named .../templates/com.mycompany/MyFlowAction.<flowView>.jsp. These templates will be invoked for the mentioned beans of type WebflowActionState.

  3. Create (and integrate) a new document of type CMAction and set the property id to the action id (such as com.mycompany.MyFlowAction) and the property type to webflow.