Blueprint Developer Manual / Version 2207
Table Of ContentsRequirements
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 Content Application 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.
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>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.
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
originalas well asrequestare 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
modelAttributecauses the substitution to be become available as a request attributesubscriptionForm. This is useful when using dealing with the Spring form tag library (see above).
Create a newsletter action content
Create a content of type
CMActionSet the
idproperty to valuecom.coremedia.subscriptionInsert this content to a page's teaser link list.
Here is what happens when opening the page by sending an HTTP request:
The request will be accepted by the
PageHandlerthat builds aModelAndViewcontaining thePagemodel. This model's tree of content beans contains the newCMActioninstance.The model will be rendered by initially invoking
Page.jspfor thePagebean.When the
CMActionis going to be rendered in the teaser list, the templateCMAction.asTeaser.jspis invoked. This template substitutes theCMActionbean by invoking thecm:substitutefunction while using the IDcom.coremedia.subscription.The substitution framework invokes the method
#createSubscriptionSubstitutionafter checking whetherSubstitutionRegistry#registerhas been invoked by any handler for his ID (which hasn't happened here). As the result, the substitutions result is a bean of typeSubscriptionForm.The above mentioned template
CMAction.asTeaser.jsptherefore delegates toSubscriptionForm.asTeaser.jspthen.While rendering
SubscriptionForm.asTeaser.jsp, a link pointing to this form bean is going to be built. The method#createSubscriptionLinkis chosen as a link scheme so that the link points to the handler method#handleSubscription.After the user has received the rendered page, he might enter his email address and press the submit button.
This new (POST) request is accepted by the mentioned handler method
#handleSubscriptionthat 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.
Place your flow definition file somewhere below a package named
webflowsomewhere in the classpath. The name of the flow definition file should be<action_id>.xml. Example: For an actioncom.mycompany.MyFlowActionyou might create a filecom.mycompany.MyFlowAction.xmlthat can be placed below a packagecom.coremedia.blueprint.mycompany.webflow.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.MyFlowActionrequires templates to be named.../templates/com.mycompany/MyFlowAction.<flowView>.jsp. These templates will be invoked for the mentioned beans of typeWebflowActionState.Create (and integrate) a new document of type
CMActionand set the propertyidto the action id (such ascom.mycompany.MyFlowAction) and the propertytypetowebflow.


