Tuesday, 28 April 2015

Use of pageLayoutCache JSTL tag and PageDesignMetaDataGenerator

Typically when servlet caching is enabled in WCS for Store JSPs, top level browsing pages like ProductDisplay, CategoryDisplay, HomePage are cached. These pages are cached on the input parameters to the view.

For example, ProductDisplay view will be cached on productId or partNumber, storeId, langId, catalogId. Once the page is cached, the next step is to identify the dependency Id's based on the content displayed by the view, so that the cache can be invalidated whenever the content of the page changes. 
So for example, if page displays both offerPrice and listPrice, then dependency Id's will be added for each price, so that even if one of the price changes entire cache gets invalidated.

Prior to Feature Pack 7, the ProductDisplay page was built by IT team and they typically updated the cachespec.xml to add dependency ids, cache attributes etc., based on page contents.

But starting with feature pack 7, business users have ability to use commerce composer to modify the page contents ( add / remove widgets ) as well as schedule the priority, start date / end date for the layouts. Which means, ProductDisplay page dependency Id's cannot be statically added to cachespec.xml during Code and UT phase. The dependency Id's needs to be added dynamically at runtime based on the layout attributes set by business users.

WebSphere Application Server cache module provides a way to programmatically decide whether to cache a page or not and also to add dependency Id's and set cache time out values at run time. This is achieved through MetaDataGenerator class and <metadatagenerator> tag in cachespec.xml.

WCS makes use of this feature to manage the cache properties dynamically at runtime.
 So a new class com.ibm.commerce.pagelayout.cache.PageDesignMetaDataGenerator is created and following tag is added to top level cache entries in cachespec.xml

<metadatagenerator>com.ibm.commerce.pagelayout.cache.PageDesignMetaDataGenerator</metadatagenerator>

PageDesignMetaDataGenerator gets executed for every request. This metaDataGenerator class will identify all the eMarketing Spots and activities responsible for displaying the layout. (Commerce composer uses Marketing runtime under the hood to associate layouts with pageObjects like product pages, category pages, static pages). Once the eMarketingSpots are identified, it checks if these eSpots are static or dynamic in nature. If the eSpots are static then metaDataGenerator decides to cache this page and sets the timeOut value based on the eSpot attributes. If the eSpot is dynamic then metaDataGenerator makes it non cacheable request.

Since business user have the ability to change the layout (add widget, remove widget, change widget properties ) using composer tool, the cache needs to be invalidated dynamically as and when business user changes the layout. 

Communication between composer tooling and layout cache happens through dependency id's and invalidation id's. Whenever business user modifies the layout, pageLayout:<layoutId> dependency id is published by the composer tool.
The cache entry will have pageLayout:<layoutId> as one of it's invalidation id. So when dependency Id pageLayout:<layoutId> is published, the cache gets invalidated.

But how will someone add pageLayout:<layoutId> as invalidation Id to the cache entry ? Obviously it cannot be added statically in cachespec.xml, since layoutId is determined at runtime.

One option is to make use of MetaDataGenerator to identify the layoutId. But as we know, MetaDataGenerator gets executed for every request ( even if request is eventually served from cache ). So identifying the layoutId by executing pageDesign handler in metaDataGenerator for every request is very expensive operation and defeats the whole purpose of caching.

This is where <wcpgl:pageLayoutCache> JSTL tag comes into picture. This tag needs to be included on every layout JSP page. This tag makes use of the pageDesign object available in JSP and retrieves the layoutId from pageDesign object. It adds pageLayout:<layoutId> as one of the dependency id to the cache entry. Since layout details already fetched in the JSP, the tag doesn't make any additional service call. Also when the request is served from cache, the JSP never gets executed and hence there is no overhead with this approach.

So in summary, whenever layout JSP ( the top level JSP, which has an entry in struts-config-ext.xml + makes a call to pageDesign object to retrieve the layout information ) is cached, the following additional steps should be done:

1) Add <metaDataGenerator> tag to the cache entry in cachespec.xml - This tag decides whether to cache the request or not. If cached, adds timeOut value and emsName:<name> as one of the dependency id. This helps to invalidate the cache whenever layout association changes.
2) Add <wcfpgl:pageLayoutCache> into JSP - This tag adds pageLayout:<layoutId> as one of the dependency id, so that when layout design changes, the cache gets invalidated.


Wednesday, 22 April 2015

Invoking REST Services ( PUT / POST / DELETE ) from Store JSP

In this section we will look at how to invoke REST Services ( POST / PUT / Delete ) from Store JSPs using WCS framework.

Let's assume that you want to update quantity of an existing orderItem using REST Service. Looking at the swagger documentation we see that the REST URL to update an orderItem is:


https://localhost/wcs/resources/store/10001/cart/@self/update_order_item
HTTP Method is: PUT


Now to test this REST URL, you can use any REST Client (like HTTP Requester for FF or POSTMAN for chrome) and do a PUT with the JSON body set to something like below:


{

"orderId" : "123",
"orderItem" : [
      {
            "quantity" : "4", // New quantity
            "orderItemId" : "1212",
      }
   ]
}

 
Lets see how you can invoke this REST Service from JSP. Say, you have a shopping cart page where customers are allowed to modify the quantity and hit a submit button to save it. So how do you invoke a REST action and POST / PUT a JSON body as part of form submission ? Who converts the name value pair to JSON input required for the REST call ?

WCS framework provides you an Action class (RESTAction) to achieve this in a much simpler way. Its as simple as invoking a controller command from a view. Following list gives you step by step instructions to do the same:

  1. Create a mapping in rest-template-config.xml in Stores.war/web-inf/config/com.ibm.commerce.order-fep/rest-template-config.xml OR in your own XML file inside Stores.war/web-inf/config/<yourDir>. Make sure your XML file name ends with rest-template-config.xml 
rest-template-config.xml Mapping

  • Resource path ${serverHost}/wcs/resources/store/${storeId}/cart is mapped to name "orderlist".
  • HTTP PUT Method for path @self/update_order_item is mapped to name updateOrderItem
  • Input name value parameters are mapped to JSON structure inside <template> tag.
Update struts-config-order-rest-services.xml (or your custom struts file) to create a mapping URL as shown below:

Struts mapping entry.
  • parameter value refers to resourcePathName.methodName defined in rest-template-config.xml.
  • type is set to AjaxRESTAction. If you like to invoke the REST Service in Web1.0 style without using Ajax, then change type to RESTAction
With the above setup done, you can now submit the HTML Form to "AjaxRESTOrderItemUpdate" and pass name value parameter.

So the final URL to which HTML form will be posted looks something like:
https://localhost/webapp/wcs/stores/servlet/AjaxRESTOrderItemUpdate?orderId=123&orderItemId=123&quantity=4

This request is handled by the Store Struts servlet which invokes AjaxRESTAction class. This action class builds the complete REST URL and the JSON body using the mappings present in rest-template-config.xml and invokes that URL either remotely (using java.net.URL object) or locally (using RequestDispatcher).

You can follow similar pattern to make POST and DELETE calls from Store JSP

Tuesday, 21 April 2015

Invoking REST Services (GET Method ) from Store JSP

WCS provides various resource handlers like CartHandler, OrderHandler, PersonHandler, PromotionHandler etc., Let us explore how to invoke GET request on these resources from one of the Store JSP code.
For illustration purpose let us assume that you want to invoke GET request on CartHandler resource to retrieve shopping cart details. CartHandler resource class is annotated with store/{storeId}/cart and getCart method is annotated with @self as shown in below code snippet.

Cart Handler



Now to invoke this REST Service from a REST Client (HTTP Requester for FF or PostMan for Chrome), you will use the below URL:

URL:
http://localhost/wcs/resources/store/10001/cart/@self?pageNumber=1&pageSize=20
HTTP Method –> GET
JSON Body -> NULL

Note:
wcs/resources is the context path for Rest.war. All REST Handler classes are declared in Rest.war/web-inf/config/providers.properties. web.xml points to this providers.properties file as shown below:

<servlet>
  <servlet-name>JAX-RS Servlet</servlet-name>
  <servlet-class>

       org.apache.wink.server.internal.servlet.RestServlet
  </servlet-class>
  <init-param>
     <param-name>propertiesLocation</param-name>
     <param-value>/WEB-INF/config/rest-config.properties</param-value>
  </init-param>
  <init-param>
     <param-name>applicationConfigLocation</param-name>
     <param-value>

       /WEB-INF/config/providers-ext.properties;
       /WEB-INF/config/providers.properties;/WEB-INF/config/resources-ext.properties;
       /WEB-INF/config/resources.properties
     </param-value>
  </init-param>
  <init-param>
</servlet>



If you want to make use of this GET Cart Service in ShoppingCart.jsp to display the cart details, you have two options:
  1. On page load, make an Ajax call to this REST URL and build the DOM using the returned JSON object and javascript functions.
  2. Use java scriptlets on JSP code with java.net.URL object to open connection to the REST URL and retrieve the response. Then use JSTL tag library to loop through the response and build the DOM.

But if you go with second option, you have to handle exception scenario, connection timeOut issues, server hostName and portNumber configuration, caching etc.,
Luckily WCS framework helps to overcome these issues easily and provides a simpler way of invoking GET REST Services, through wcf:rest JSTL Tag.
The tag handler class RestTag encapsulates all the complexities involved in invoking the REST Service and allows UI developers to concentrate on presentation layer.

Here is the sample code to invoke the GET Service using wcf:rest tag

<wcf:rest var="myOrders" url="store/{storeId}/cart/@self">
      <wcf:var name="storeId" value = “10001" encode="true"/>
      <wcf:param name="pageSize" value="20"/>
      <wcf:param name="pageNumber" value="1"/>
</wcf:rest>
 
REST tag builds the final URL by:
  1. Converting relative URL to full URL. It looks at REST_CONFIG variable set in EnvironmentSetup.jspf file as request attribute to identify the port number, server host name etc.,
  2. Replaces variables in the URL with value passed with wcf:var tag. ( {storeId} will be replaced with 10001 ) in above example.
  3. Any value set with wcf:param tag will be passed as query parameters.
So final URL will be:
http://localhost/wcs/resources/store/10001/cart/@self?pageSize=20&pageNumber=1

So by using wcf:rest tag, you can easily invoke any GET Rest request from your JSP code.

Few other benefits of REST tag are:
  1. REST Tag also takes care of passing headers (WCToken, WCTrustedToken, Cookies etc) as part of the request.
  2. REST Tag implements caching at request level. So when GET request to same resource is invoked second time within the same request, the response comes from cache.
  3.  REST Tag takes care of Local binding / Remote binding setting done in component configuration files. So if binding is Local (Stores.war runs within WC.ear), request dispatcher is used to invoke the REST call instead of opening URL connection.

Invoking Controller Commands from Store JSP



WCS business logic layer provides various artifacts like Controller Commands, SOI Services, BOD (SOA) Services and REST Services to execute business logic. These commands and services can be invoked from view layer (For ex: Web Store) using Struts, JSTL tag libraries and WCS framework. Struts is used for managing view – controller interaction. In this post we will see how to invoke controller command from a Store JSP.

 Assume you have created a custom command implementation com.mycompany.MyOrderItemAddCmdImpl for com.ibm.commerce.orderitems.commands.OrderItemAddCmd, to add an item to shopping cart.

The list below provides high level steps required to invoke this custom command from one of the Store JSP (with StoreId = 10001)

  •  Register this command in CMDREG table by executing following insert statement.
insert into cmdreg values(10001,'com.mycompany.MyOrderItemAddCmdImpl','description','com.ibm.commerce.orderitems.commands.OrderItemAddCmd',null,null,null, 0);
  •  Update struts-config-ext.xml in Stores.war/web-inf folder with following entry

<action parameter="com.ibm.commerce.orderitems.commands.OrderItemAddCmd" path="/MyOrderItemAdd" type="com.ibm.commerce.struts.BaseAction">
<set-property property="credentialsAccepted" value="10001:P "/>
<set-property property="authenticate" value="10001:1"/>
<set-property property="https" value="10001:1"/>
</action>
  
• /MyOrderItemAdd is the mapping name which will be used in the URL to invoke MyOrderItemAddCmdImpl command.
• Set credentialsAccepted value to <storeId>:P, if this command can be executed by partially authenticated user (Remembered user)
• Set authenticate value to <storeId>:1, if this command needs to be executed by only logged in user
•  Set https value to <storeId>:1, if this command needs to be executed over secure HTTPS protocol.
•  Set type = “com.ibm.commerce.struts.BaseAction” if the command needs to be invoked in Web1.0 style. When a controller command is invoked with BaseAction, ‘URL’ query parameter is mandatory. Once the command execution completes, user will be redirected to the view specified with ‘URL’ query parameter.
•  Set type = “com.ibm.commerce.struts.AjaxAction” if the command needs to be invoked in Web2.0 style (Ajax request). When a controller command is invoked with AjaxAction, after execution of controller command, request will be forwarded to AjaxActionResponse.jsp or AjaxActionErrorResponse.jsp, which takes response properties from command, converts to JSON object and returns JSON response to client.

  
  • You can now POST form from JSP to below URL, by setting action attribute of form to /MyOrderItemAdd.
https://localhost/webapp/wcs/stores/servlet/MyOrderItemAdd?catentry_id=12345&quantity=1&URL=ShoppingCartPageView&errorViewName=ErrorPageView


Tracing the request:
webapp/wcs/stores maps to Stores.war. So request is handled by Store Webapp.

ECActionServlet is configured to handle incoming requests with path /servlet/* in web.xml and is the entry point for the request.

BaseAction / AjaxAction handles the request and reads struts-config-ext.xml entry and looks for /MyOrderItemAdd

MyOrderItemAdd maps to interface name in struts-config-ext.xml.

CMDREG contains the implementation class for this interface name.

MyOrderItemAddCmdImpl command gets invoked.

Query Parameters / Form post parameters are set into RequestProperties by base 
ControllerCommandImpl and will be available for the command to execute the business logic.


ResponseProperties will be set after successful execution of the command.