Monday, May 14, 2012

Cookie path creation always at the web server root !!

If you use the default settings on cookie, it creates the cookies at the web server context. In WebSphere commerce that would create the cookies at /webapp/wcs/stores/servlet with default settings. This is usually not a problem for most scenarios but if you have a scenario when there is a canonical URL e.g for SEO,  that does not start with /webapp/wcs/stores/servlet. The HTTP response stops carrying the cookies to the browser and you will start seeing issues in the site where you have code that depends on the cookie.


Sample code to create a custom cookie at the root:
String value="custom_cookie_value";
Cookie customCookie = new Cookie("CustomCookie",value);
customCookie.setPath("/");
Even though this is a simple thing to fix, it could be hard to debug. As a best practice, always create custom cookies at the root and out of the box cookies are always created at the root.


Primer on cookies:
A cookie is a application specific data stored as a separate file for each domain in the browser. There are 2 types, session cookies and persistent cookies. Session cookies are used to log information that are eventually erased after the life cycle of a session, e.g Based on a users Login, if you want to show certain attributes or mini-carts and are deleted on LogOff.
Persistent cookies are store for much longer period and are useful for things like RememberMe functionality.


Validation rules to pass the cookies back to web-server:
A cookie is sent back from browser to web-server based on certain events when it matches the Domain, Path and port of the server in cookie.
Cookie can have a secure attribute set if it is on HTTPS.
Each cookie has a Max-Age and the browser would not send back expired cookies.

Tuesday, May 8, 2012

Bazaar Voice Integration | Reviews and Ratings

BazaarVoice provides a really good platform for product feedback and social media integration's. It is really easy for business users and programmers to integrate with back end systems.

Essentially BazaarVoice Integration has the following main components:

1. Display reviews to guest and registered customers.
2. Writing new reviews and as a platform providing business users access to their workbench tooling to approve reviews.
3. This is optional and provides SEO benefits as the JS based integration makes it harder for search engines to crawl the content and hence BazaarVoice provides SEO basic and SEO advanced integration's, this is a server side include of product files.
4. Sending outbound XML product feed to BazaarVoice nightly or weekly feed of categories and products, depending on your product cycle.
5. Feeding reviews and ratings file from BazaarVoice back to your Search engine (Endeca or SOLR).  This is to improve the search on the site by allowing keywords from reviews to be searchable.
Find below sample code for a simple integration piece to show reviews.




Resources: Great place with examples.
https://github.com/bazaarvoice/HostedUIResources

Sunday, April 29, 2012

Adding cache-control on static assets | Improve data integrity and performance


Static files (example: JS\CSS\HTML.) are cached by client browsers and if they don't carry cache-control directive in the HTTP-header, it is up to the browsers to determine, how often to check to check for updated value from server. Some times browsers could cache stale content for days.
This could cause the static file to be obsolete and pick from local browser cache and out of sync and could potentially result in broken pages and corrupt files.
The solution is to add cache-control directive to the web server configuration and this will force the browser to check for the updated version from the server when the time specified expires.
The functionality would essentially result in HTTP_STATUS code 200 when a file is modified and other wise would return HTTP_STATUS code 304

Testing the HTTP-Header changes:
You can using tamper data as Firefox plugin or fiddler for IE to look at the HTTP-header

Make changes to httpd.conf
1. Add the following at the end of LoadModule section in web server configuration file (httpd.conf).
        LoadModule headers_module modules/mod_headers.so
2. Add the following at the end of web server configuration file (httpd.conf).


Scenario1: [Browser cache not expired and file changed - File should be fetched with 200 response]
Scenario2: [Browser cache expired and file changed - should be fetched from server with 200 response]
Scenario3: [File not changed but browser cache expired - should get 304 response]
Scenario4:[File not changed and browser cache not expired - should be serverd from browser cache]

Friday, April 27, 2012

Sorting !!! an important function for a lot of display pages

This blog is for sorting using Java code. Sorting is an essential part, which is a required function in most code bases.I am going to start with a couple and then will add few more. If you any of you guys reading this have better ideas, please add in the comments.

//Sort a string with a delimiter and arrange with the same delimiter into a string Arrays.sortOf() uses merge sort and has a worst case performance O(nlogn)
//Sort and maintain the same ordering. LinkedHashMap is very useful to preserve the ordering. It Maintains a doubly-linked list running through all of it's entries

Saturday, March 31, 2012

Introduction to WCS Cache Invalidation - Part 1

"There are only two hard problems in Computer Science: cache invalidation and naming things."
-- Phil Karlton

As the quote above suggests cache invalidation can be a complex topic.
In this post will discuss the basics of cache invalidation; along with some guidelines for the different invalidation strategies that can be used with WebSphere Commerce.
This guide assumes some familiarity with configuring caching in WebSphere.

What is cache invalidation ?
Essentially it is the mechanism of removing the stale items from cache.
WebSphere Commerce has a caching system called DynaCache.

Why is invalidation important?
To protect the accuracy of the data available in cache. 
Most business applications have a consistency requirement for certain types of data.
For example, If my inventory reaches zero, I don't want the customer to purchase items which have no inventory and which can not be back-ordered.

How can I invalidate cache?
Here is a list of the different ways you can invalidate cache:
  1. Manual Invalidation
  2. Time to Live (TTL)
  3. Dependency IDs
    1. Using command invalidation
    2. Using CACHEIVL (only in WebSphere Commerce)
    3. Using custom code
Manual Invalidation
This type of invalidation is done by using the WebSphere Commerce Cache Monitor.
The cache monitor is a web application which uses the DynaCache API to remove specific entries.

The EAR file comes with WebSphere Application Server but it is not installed by default.
Make sure servlet caching is enabled in your WCS environment before installing the Cache Monitor.

The advantage of this method is that you can invalidate all entries at the same time by pushing a button.
You can also invalidate only a given group of entries. This is a more complex topic which will be explained in a later post.

The disadvantage is that if you have a large number of entries it will be difficult to find a specific entry.
There is no search capability and the navigation is not very user friendly.

Invalidation using a TTL
The TTL value is configured in cachespec.xml.
A <timeout> child element is added to a <cache-entry> element. The timeout is specified in seconds.
This type of invalidation is best used when you don't have a hard consistency/freshness requirement.

Let's use the caching of the product display page as an example
For this example we will assume the following:
  1. The product table is updated once a day
  2. The update is done by a scheduled job
  3. The scheduled job runs once a day at 10pm
In this case it would make sense to set the TTL for ProductDisplay to 86400 (seconds in a day):



The timeout starts from the time each cache entry is created. Each product has a separate cache entry which is created when a page for a specific product id or part number is accessed. Since each cache entry could be created at a different time, they could also expire at a different time.

The advantage of this method is that it is easier to configure compared to dependency ID invalidation.

The main disadvantage of using TTL invalidation is that there is no guarantee that the cache will expire before the product table is updated.

Here is a scenario where the cache would not be properly invalidated:
  1. Most cache entries expire around midnight.
  2. The scheduled job is delayed due to some problem.
  3. A user access the product page for part number ABC at 12:30am creating a new cache entry
  4. The scheduled job updates the data for ABC and finishes running at 1am
  5. The product page for ABC is not updated because the timeout value was reset at 12:30am

Ideally the product update job should always run before the cache expires, but in this case it didn't.
The easiest solution in this case is to do a manual cache invalidation at 1am after the scheduled job has finished running.

Another disadvantage is that all the entries will expire around the same time. This will cause a large number of requests to hit WebSphere Commerce at the same time without the benefit of a cached response. This will degrade the performance perceived by the user.

In conclusion this method is best used when:
  1. You have a low consistency business requirement: The cache can be updated sometime after the database is updated.
  2. You have the operational resources: Someone is watching the scheduled job to see if it is delayed and if something goes wrong he knows to manually invalidate the cache.

NOTE: The <timeout> value is separate and different from the <inactivity> value. It is possible to have both settings. The <inactivity> value will expire the cache after it has not been accessed for a given number of seconds.

Stay tuned for the next post which will cover dependency ID based cache invalidation ...

Wednesday, March 28, 2012

A Classic case of redirect and passing objects !!

Redirect does not support passing objects back to view. I am sure, we have all tried to pass an object or ArrayList of objects to make a pretty URL in the browser or convert a POST request to a GET and so instead of doing a forward, we try to do redirect  from a command\controller to a view.

Controller command:
In JSP:

Error:
Unable to find a value for "methodName" in object of class "java.lang.String" using operator "."

HTTP redirection allows servers to redirect a client request to a different location. A POST request can be a converted to a GET request using redirection with a status code 302.A server specifies redirection by sending 3XX status code.
Redirect is done via  URL and hence can only support name/value pair. Forward works with Objects but redirects can not pass objects back to the view. When trying to access the object retrieved from WCParam, it throws the above exception.

Alternate Solutions: If you do need to pass an object on redirect.
1. Putting object in HTTPSession (Not recommended as it could use a ton of memory in application server depending on how many users hit the URL)
2. Serialize objects in a XML/JSON String, like what Accelerator does.
3. Commerce context services, customize a commerce service for storing session information and store in database.


Thursday, March 8, 2012

Demonstrating an Industry Standard Search Solution


Demonstrating an Industry Standard Search Solution

IBM WebSphere Commerce is now a fully operational search engine.
The product now includes Lucene Solr (http://lucene.apache.org/solr/) as the internal search engine, thus not only leveraging open standards, also incorporates industry best practices.

With that, you will probably benefit to enable the IBM WebSphere Commerce search capability in a starter store, so that you can get a good idea what is available out-of-the-box with the product.

Here is a link to the IBM WebSphere Commerce information center documentation regarding WebSphere Commerce search:
http://publib.boulder.ibm.com/infocenter/wchelp/v7r0m0/topic/com.ibm.commerce.developer.doc/concepts/csdsearch.htm

At a high level, WebSphere Commerce search provides the following key business benefits:

  • It is built on the top of open architecture.
  • It contains a rich set of search functionality for shoppers in starter stores.
  • It provides integrated search management tooling for business users in the Management Center.
  • It lowers the total cost of deployment and ownership, since its functionality is included as a feature of WebSphere Commerce.


In regards to starter stores, here is a link to the IBM WebSphere Commerce information center to summarize what is available-to-market in the product:
http://publib.boulder.ibm.com/infocenter/wchelp/v7r0m0/topic/com.ibm.commerce.starterstores.doc/concepts/csmsearch.htm

This blog entry covers the steps required to enable search for a starter store.

This is where you should start to understand how to setup search for a starer store:
http://publib.boulder.ibm.com/infocenter/wchelp/v7r0m0/topic/com.ibm.commerce.starterstores.doc/refs/rsdfepfeatroadmap.htm

As a side note to this link, I was only able to install Feature Pack 2, due to limited resource access, but I still brought IBM WebSphere Commerce up to Fix Pack level 5 (WCS v7.0.0.5).

The following list of steps is the procedure that I took in order to enable a fully integrated search solution into a demonstrable starter store:

  1. Install "WebSphere Commerce Developer Enterprise" version 7
  2. Update "WebSphere Commerce Developer Enterprise" to version 7.0.0.5
  3. Install "Feature Pack 2" (preferably feature pack 3 or higher)
  4. Enable the Store Enhancement Features
    1. cd 'WCDE_installdir'\bin
    2. enableFeature.bat -DfeatureName=store-enhancements
  5. Publish the Madisons Feature Pack Store Archive:
    1. Publish Madisons-FEP.sar
  6. Enable the Solr foundation
    1. cd 'WCDE_installdir'\bin
    2. enableFeature.bat -DfeatureName=foundation [DsolrHome=C:\IBM\WCDE_ENT70\search\solr\home]
  7. Setup the Search Index:
    1. cd 'WCDE_installdir'\components\foundation\subcomponents\search\bin
    2. setupSearchIndex.bat -masterCatalogId 10001 -instance WCDE_ENT70 -dbuser db2admin -dbuserpwd db2admin [-solrhome C:\IBM\WCDE_ENT70\search\solr\home]
  8. Preprocess the Search index:
    1. cd WCDE_installdir\bin
    2. di-preprocess.bat C:\IBM\WCDE_ENT70\search\pre-processConfig\MC_10001\DB2\ [-fullbuild true] [-localename en_US]
  9. Test the current Solr index to ensure that a request can be recognized:
    1. http://host_name/solr/Default/select?q=*%3A*
  10. Build out the index (first make sure to start the test server in toolkit):
    1. cd 'WCDE_installdir'\bin
    2. di-buildindex.bat -masterCatalogId 10001 
  11. Test the indexed Solr index to ensure results are returning:
    1. http://localhost/solr/MC_10001_CatalogEntry_en_US/select?q=catentry_id:10251
  12. Enable the store to display the search breadcrumb and faceting filters:
    1. Open Management Center
    2. Click "Management Center Tools" menu and select "Store Management"
    3. Select the "Madisons" store and click the "Catalog" tab
    4. check "Search-based navigation"
    5. click Save
  13. Test live on the starter store:
    1. http://localhost/webapp/wcs/stores/servlet/Madisons/index.jsp
    2. http://localhost/webapp/wcs/stores/servlet/Elite/index.jsp