One of the most used features in a Aurora front-end is the category list view using facet filters

AuroraProductGridWithFacets

To increase the usability of this important feature, it’s mandatory to configure dynacache to handle user interactions with the filters.

When you select a facet like “Color” or “Available Sizes” or you hit the page number to scroll into results, you always execute an AJAX action called “CategoryNavigationResultsView”. For instance if I press the “(Blue)” link in the “Color” facet, this XHR request is generated.

AuroraCategoryNavigationResultsViewExecutionOneFacets

and 78 queries are executed in the background against the DB

AuroraCategoryNavigationResultsViewExecutionOneFacets_SQLProfiler

Associated to this request, an entry is generated in dynacache and that entry has “ads_f10501_ntk_cs%3A%22Blue%22″ as facet value.

Facet values are the key to correctly cache grid pages because facet parameter is a multi value parameter.

If you now choose “M” in the “Available Sizes” to filter “M” sizes between the blue dresses, facet parameter become an array using 2 values.

AuroraCategoryNavigationResultsViewExecutionTwoFacets

The only way to handle this in the dynacache configuration is to use a parameter-list component for the facet

<component id=”facet” type=”parameter-list“>
<required>false</required>
</component>

then the cache-id for the CategoryNavigationResultsView XHR request will be

<cache-id>
<component id=”" type=”pathinfo”>
<required>true</required>
<value>/CategoryNavigationResultsView</value>
</component>
<component id=”storeId” type=”parameter”>
<required>true</required>
</component>
<component id=”langId” type=”parameter”>
<required>true</required>
</component>
<component id=”catalogId” type=”parameter”>
<required>true</required>
</component>
<component id=”categoryId” type=”parameter”>
<required>false</required>
</component>

<component id=”facet” type=”parameter-list“>
<required>false</required>
</component>

</cache-id>

Using this parameter type, dynacache engine will be able to store all the facet values associated to the request and put them as a key in the cache entry

Cache Entry:
/webapp/wcs/stores/com.ibm.commerce.struts.ECActionServlet.class:pathinfo=/CategoryNavigationResultsView:storeId=10202:langId=-1:catalogId=10051:categoryId=10056:pageView=grid:beginIndex=0:pageSize=12:searchType=:sType=SimpleSearch:resultCatEntryType=:metaData=:orderBy=:orderByContent=:

facet=ads_f10001_ntk_cs%3A%22M%22,ads_f10501_ntk_cs%3A%22Blue%22:

filterFacet=:manufacturer=:minPrice=:maxPrice=:contentBeginIndex=0:isHistory=false:productBeginIndex=0:requesttype=ajax:objectId=:resultType=products:searchTerm=:UTF-8:requestType=POST

not only store the first one

Cache Entry:
/webapp/wcs/stores/com.ibm.commerce.struts.ECActionServlet.class:pathinfo=/CategoryNavigationResultsView:storeId=10202:langId=-1:catalogId=10051:categoryId=10056:pageView=grid:beginIndex=0:pageSize=12:searchType=:sType=SimpleSearch:resultCatEntryType=:metaData=:orderBy=:orderByContent=:

facet=ads_f10501_ntk_cs%3A%22Blue%22:

filterFacet=:manufacturer=:minPrice=:maxPrice=:contentBeginIndex=0:isHistory=false:productBeginIndex=0:requesttype=ajax:objectId=:resultType=products:searchTerm=:UTF-8:requestType=POST

Special thanks to Kevin Ortega (IBM) to help me find out this.

Posted by: Marco Fabbri | March 21, 2013

How to troubleshoot stagingprop execution in DB2

If you didn’t apply FP6 yet, you can’t use the -trace parameter

[stagingprop utility]

http://pic.dhe.ibm.com/infocenter/wchelp/v7r0m0/topic/com.ibm.commerce.admin.doc/refs/rssstageprop.htm

and even in that case you can only choose between 4 predefined trace levels

0 – (default) High-level summary only.
1 – Table level information and Global summary report.
2 – Table summary report and row level information.
3 – SQL statements and diagnostic.

But stagingprop is using a JDBC type 4 connection underlying

“Note: For DB2 UDB databases, the DB2 Type 4 JDBC driver is used, where the Type 4 database name is prefixed with the database server and port. For example, db_server:db_port/db_name.”

This means you can trace stagingprop execution exactly as you do with any other JDBC type 4 connection using the DB2 JCC driver

[Collecting Data: Tracing with the IBM Data Server driver for JDBC and SQLJ]

http://www-01.ibm.com/support/docview.wss?uid=swg21196160

To apply the technote to the Commerce environment, you just need to “play” a bit with the JDBC url parameters

String databaseUrl = “jdbc:db2://localhost:50000/sample”
+ “:traceDirectory=c:\\temp”
+ “;traceFile=trace”
+ “;traceFileAppend=false”
+ “;traceLevel=”
+ (com.ibm.db2.jcc.DB2BaseDataSource.TRACE_ALL)
+ “;”;

The standard way to execute stagingprop command is specifying the db name only (DB2SRCDB and DB2TGTDB)

./stagingcopy.sh -scope _all_ -sourcedb DB2SRCDB -sourcedb_user dbsrcuser -sourcedb_passwd dbsrcpwd -destdb DB2TGTDB -destdb_user dbtgtuser -destdb_passwd dbtgtpwd

but if you apply a specific JDBC URL syntax

./stagingcopy.sh -scope _all_ -sourcedb “DB2SRCSRV:<port>/DB2SRCDB:traceFile=/var/log/stagingTrace.log;traceLevel=567″ -sourcedb_user dbsrcuser -sourcedb_passwd dbsrcpwd -destdb “DB2TGTSRV:<port>/DB2TGTDB:traceFile=/var/log/productionTrace.log;traceLevel=567″ -destdb_user dbtgtuser -destdb_passwd dbtgtpwd

you will be able to trace stagingprop execution using the trace level you need activating correspondent trace flags

“If the URL is specified outside application code, specify a numeric value for traceLevel. Possible values:

  • TRACE_NONE (blank)
  • TRACE_CONNECTION_CALLS (1)
  • TRACE_STATEMENT_CALLS (2)
  • TRACE_RESULT_SET_CALLS (4)
  • TRACE_DRIVER_CONFIGURATION (16)
  • TRACE_CONNECTS (32)
  • TRACE_DRDA_FLOWS (64)
  • TRACE_RESULT_SET_META_DATA (128)
  • TRACE_PARAMETER_META_DATA (256)
  • TRACE_DIAGNOSTICS (512)
  • TRACE_SQLJ (1024)
  • TRACE_XA_CALLS (2048)*
  • TRACE_META_CALLS (8192)
  • TRACE_DATASOURCE_CALLS (16384)
  • TRACE_LARGE_OBJECT_CALLS (32768)
  • TRACE_SYSTEM_MONITOR (131072)
  • TRACE_TRACEPOINTS (262144)
  • TRACE_ALL (-1)”
Posted by: Marco Fabbri | March 12, 2013

Estimate memory needed for dynacache and Commerce data cache

To find out how much memory is used for cache it’s not a simple task. You should take several heapdumps under load, take into account disk offload, replication and see the total size of com.ibm.ws.cache.Cache just to start.

Then estimate how much memory you will have to dedicate to cache in your production server could be tricky. And more in Websphere Commerce where the cache entries were developed without implementing the com.ibm.websphere.cache.Sizeable interface. Until today.

Now an APAR is available to allow Websphere Commerce administrators to estimate the needed memory for Dynacache y Commerce data cache

[JR43804: CMVC 223884 - TO HAVE THE CACHE ENTRIES IMPLEMENT SIZABLE]

http://www-01.ibm.com/support/docview.wss?uid=swg1JR43804

It’s a recommended fix for performance and stability

[Additional fix pack APAR fixes available from Support]

http://pic.dhe.ibm.com/infocenter/wchelp/v7r0m0/topic/com.ibm.commerce.install.doc/refs/rig_new_and_changed_support.htm

To activate this feature you have to specify a value for the property memoryCacheSizeInMB  in the cache instance

Memory size in baseCache instance

or in the DistributedMap object cache (using cacheinstances.properties file)

cache.instance.x.memoryCacheSizeInMB=X

you’d like to estimate.

Then you have to add a new attribute (“sizeable”) to CrossTransactionCache tag in the wc-server.xml file

<CrossTransactionCache
clearCacheOnMaxInvalidationIdsPerTransaction=”false”
clearUserDataCacheOnLogoff=”false” clearUserOnLogoff=”true”
commandCaching=”default” defaultResultSizeThreshold=”8″
enabled=”true” sizeable=”true”

Now you are ready to test.

Starting from now all the “activated” cache instances and the Distributed maps will show the correspondent memory estimation in Cache Monitor.

Cache monitor with memory estimation

In this sample I specified “memoryCacheSizeInMB” value in the baseCache instance and I can see the 3 entries are using about 160 kb of memory heap.

There are some considerations to do.

These numbers are estimations

“Note:  While DynaCache automatically implements the Sizeable interface for servlet (JSP) cache entries, test results have
shown that the sizes calculated for these entries can be significantly underestimated.”

But during a load test, this a valuable tool to evaluate how much memory will needed on production system and to try to keep all cache entries in memory if it’s possible. And, as I said, it could be very complicated to estimate memory usage for the already 20 DistributedMaps available if you are using Commerce Data Cache.

Using this feature you can generate a “confirmation” heapdump instead of spend time using it to calculate memory cache footprint every time.

Last thing: Extended Cache Monitor has a problem with properties file and label are not shown correctly.

I fixed that (very easy) and here you can find the working version.

Most of the websites today are using a CDN to serve static contents.

And typically they are using a second level domain like static.website.com.

You need to store this domain name somewhere and use it in the JSPs; there are several ways to do this but I think the more elegant is to use a table created with FEP4 and an existing noun.

The table is the STORECONF and it’s created during the foundation feature enablement

[Application changes when you enable foundation]

http://pic.dhe.ibm.com/infocenter/wchelp/v7r0m0/topic/com.ibm.commerce.install.doc/refs/rig_foundation_fileschanged_fep4.htm

In that table you can store name-value pairs and use it in the application.

If you enabled Facebook integration in FEP4, you’re already using this feature

[Inserting a Facebook Application ID into your store]

http://pic.dhe.ibm.com/infocenter/wchelp/v7r0m0/topic/com.ibm.commerce.starterstores.doc/tasks/tsm_fbintconfigfbappID.htm

because inserting this record

insert into storeconf values (store_id,’wc.facebook.application_id’, ‘fb_app_id_rt’, 0);

and creating this JSPF page

[Updating store JSP files to add Facebook buttons]

http://pic.dhe.ibm.com/infocenter/wchelp/v7r0m0/topic/com.ibm.commerce.starterstores.doc/tutorial/tsm_fbintmobile_1.htm

JSTLEnvironmentSetupExtForFacebook.jspf

your application is calling the OnlineStore noun

<wcf:getData type=”com.ibm.commerce.infrastructure.facade.datatypes.OnlineStoreType” var=”onlineStore” expressionBuilder=”findByUniqueID”>
<wcf:param name=”storeId” value=”${storeId}” />
<wcf:param name=”accessProfile” value=”IBM_Details” />
</wcf:getData>

and the UserData section of this noun (check it opening the [WCDInstallation]\workspace\WebServicesRouter\WebContent\component-services\xsd\OAGIS\9.0\Overlays\IBM\Commerce\Resources\Nouns\OnlineStore.xsd with your RAD) is reading from the STORECONF table

<c:set var=”facebookAppId” value=”${onlineStore.userData.userDataField['wc.facebook.application_id']}” scope=”request”/>

Then it’s quite simple to use it in a JSP.

First you create a new record in STORECONF associated to the domain

insert into storeconf values (store_id,’wc.static.domain’, ‘static.website.com’, 0);

put it in a JSTL variable

<c:set var=”staticDomain” value=”${onlineStore.userData.userDataField['wc.static.domain']}” scope=”request”/>

and you’re ready to use it in a link.

If you are working with Extended Sites and you have defined your price lists

Madisons Price Lists

and your price rules

Madisons Price Rules

following this tutorial

[Updating the List price rule of extended site stores]

http://publib.boulder.ibm.com/infocenter/wchelp/v7r0m0/topic/com.ibm.commerce.admin.doc/tasks/tpisetuplistrule.htm

you can show list price and offer price prices using DisplayPrice noun.

This sample in the infocenter

[Customizing store page JSP files to display the list price]

http://publib.boulder.ibm.com/infocenter/wchelp/v7r0m0/topic/com.ibm.commerce.admin.doc/tasks/tpisetupjsps.htm

shows how to use the DisplayPrice noun through a wcf:getData tag

<wcf:getData type=”com.ibm.commerce.price.facade.datatypes.DisplayPriceType” var=”displayPriceType” expressionBuilder=”getDisplayPriceByCatalogEntryIdandPriceRuleName”>
<wcf:contextData name=”storeId” data=”${param.storeId}”/>
<wcf:param name=”catEntryId” value=”${catalogEntryIdForPriceRule}” />
<wcf:param name=”priceRuleName” value=”${defaultDisplayPriceRuleName}” />
</wcf:getData>

to display the price associated with the price rules previously defined on Management center

Posted by: Marco Fabbri | February 25, 2013

Using default catalog FEP5 feature in a JSP

If you upgraded to FEP5, you can finally have the default catalog feature available in your environment.

Then you can associate to your store a specific catalog from Management Center and remove catalogId references from your URLs.

The problem is: how to modify pages to use this valuable feature?

The FEP5 adoption PDF give us the solution to migrate SEO URLs but how to reflect this in a WC JSP page?

Using a wcf:getData tag as usual, taking advantage of the extended OnlineStore noun.

The default index.jsp in the front asset store has the same logic from many years: “show the first sales catalog available”

<c:if test=”${!empty storeDB.salesCatalogs}”>
<c:if test=”${!empty storeDB.salesCatalogs[0]}”>
<c:set var=”catalogId” value=”${storeDB.salesCatalogs[0].catalogId}”/>
</c:if>
</c:if>

After setting up the default catalog in the Management Center, it’s time to change this.

The code is quite simple: first get the store object using the SOI call

<wcf:getData type=”com.ibm.commerce.infrastructure.facade.datatypes.OnlineStoreType” var=”onlineStore” expressionBuilder=”findByUniqueID”>
<wcf:param name=”storeId” value=”${param.storeId}” />
</wcf:getData>

put the default catalog in a JSTL variable

<c:set var=”defaultCatalog” value=”${onlineStore.defaultCatalog[0].uniqueID}” />

and then change the URL generation using that parameter

<wcf:url var=”homePageUrl” patternName=”HomePageURLWithLang” value=”TopCategories”>
<wcf:param name=”langId” value=”${langId}” />
<wcf:param name=”catalogId” value=”${defaultCatalog}”/>
<wcf:param name=”storeId” value=”${storeId}”/>
</wcf:url>

This change on index.jsp will also allow to use the default catalog in the store preview feature because StoreView command will call the same JSP. Thanks to Francisco Fernandez to help me test this solution.

Posted by: Marco Fabbri | February 22, 2013

How to choose which fixes to install between fixpacks releases?

Normally IBM makes available two or three fixpacks for year for Websphere Commerce.

To be aware there is an important fix to install before next FP release, let’s check this infocenter page

[Additional fix pack APAR fixes available from Support]

and look for the “Recommended fix”.

If you don’t want to wait next infocenter refresh, add this feed to your reader

[Websphere Commerce Enterprise RSS Support Feed]

How can I be sure I didn’t forget something on my dynacache and data cache configuration?

Quite easy: if you missed cache entries on cachespec.xml or some configurations in the cacheinstances.properties, your DB will execute much more queries than expected.

And the best way to find out if you’re in trouble is to ask to DB administrators to generate a simple report with the most executed and the most resource intensive queries.

I give you some advices on what you should ask to an Oracle admin.

First of all ask if the Oracle statspack is installed. And if you’re working with Oracle 10g or higher, you should use the AWR acronym to be correct.

If the AWR is installed, the steps are quite simple (this is the short version):

1) Run the SQL

sqlplus / as sysdba
SQL> @?/rdbms/admin/awrrpt.sql

2) Choose HTML as format

3) Choose the day interval and the snapshot in the interval

4) An HTML file is generated on the absolute path you choose

The report is perfect for your goal: if a Websphere Commerce catalog query (for example) appears ahead in the “SQL ordered by Executions” section, you have to check your cache configuration. Associate the query to the cache entry is a bit more complicated but SQL Profiler can help you with this.

Thanks to @JAPiDBA for sharing this procedure with me.

Using an Oracle RAC is fully supported in Websphere Commerce v7 from FP2 but I think some tips are welcomed because there are several docs to read.
1) Validating the Oracle Environment for use with WebSphere Commerce

This technote is still valid in v7 and it’s very important to be sure WC utilities like massload will work because those utilities use the “old” OCI connection.

2) Creating the WC instance, you always have to point to the first RAC node

From the WC7 Infocenter:

“Database name
Any SID on nodes of Oracle RAC, for example, instance_1. Make sure you specify the SID of one of the nodes, not the service name. The name you provide for the Database Name, must be the same as the Oracle SID.”
3) The jdbc URL in the WC Datasource has to point to the RAC cluster

From the WC7 Infocenter:

“Ensure that the JNDI name shown for the WebSphere Commerce Oracle data source is as follows:
jdbc:oracle:thin:@SCAN:port/service name”

Then you have to change it after instance creation and be sure to use the Oracle SID as service name.

Probably IBM will follow Oracle guidelines in v8 using the global database name in every step.

Thanks to David Iglesias to share with me his setup experience and to the WC L2 support (very smart as usual :-))

Starting from FEP3 you can use a new set of snippets to optimize information retrieval for product pages while navigating your catalog.

Those sample assets are both for Madisons and Elite frontasset stores and allows you to exploit the usage of the new noun available from FEP3, the CatalogNavigationView noun.

Based on WC infocenter documentation, to use those assets you should:

“To enable the catalog programming model sample assets and directory structure, you must perform the following tasks:
1. Enabling starter store enhancements

2. Publishing the Madisons enhancements store archive

3. Enable Search-based navigation in the Madisons starter store

4. Copy the sample JSP file assets into the Madisons starter store directory structure, replacing the existing files with the catalog programming model sample files.”

The last step is quite simple: you just have to overwrite the files in

C:\IBM\WCDE_ENT70\workspace\Stores\WebContent\MadisonsStorefrontAssetStore\ShoppingArea

C:\IBM\WCDE_ENT70\workspace\Stores\WebContent\MadisonsStorefrontAssetStore\Snippets

with the files in

C:\IBM\WCDE_ENT70\components\store-enhancements\samples\SOACatalogStorefrontServices\stores\Madisons\ShoppingArea

C:\IBM\WCDE_ENT70\components\store-enhancements\samples\SOACatalogStorefrontServices\stores\Madisons\Snippets

Using these sample assets, you will replace catalog data beans like

<wcbase:useBean id=”product” classname=”com.ibm.commerce.catalog.beans.ProductDataBean” scope=”request” />

<wcbase:useBean id=”catEntry” classname=”com.ibm.commerce.catalog.beans.CatalogEntryDataBean”>

<wcbase:useBean id=”bundle” classname=”com.ibm.commerce.catalog.beans.BundleDataBean” scope=”request” />

<wcbase:useBean id=”item” classname=”com.ibm.commerce.catalog.beans.ItemDataBean” scope=”request” />

with the correspondent DSL (Data Service Layer) version using wcf:getData tag

wcf:getData type=”com.ibm.commerce.catalog.facade.datatypes.CatalogNavigationViewType” var=”…”

using different expressionBuilders like

getCatalogEntryViewAllByID

getCatalogEntryViewDetailsByID

getCatalogEntryViewPriceByID

getCatalogEntryViewAllByPartnumber

Replacing those files and restarting the server, you will start use the new CatalogNavigationView object to get all the informations you need to show product pages.

For example you will start getting prices directly from the CatalogNavigationView object

C:\IBM\WCDE_ENT70\components\store-enhancements\samples\SOACatalogStorefrontServices\stores\Madisons\Snippets\ReusableObjects\CatalogEntryDBThumbnailDisplay.jspf

<wcf:getData type=”com.ibm.commerce.catalog.facade.datatypes.CatalogNavigationViewType” var=”catalogNavigationView”
expressionBuilder=”getCatalogEntryViewPriceByID” varShowVerb=”showCatalogNavigationView” maxItems=”1″ recordSetStartNumber=”0″ scope=”request”>
<wcf:param name=”UniqueID” value=”${catalogEntryID}” />
<wcf:contextData name=”storeId” data=”${WCParam.storeId}” />
<wcf:contextData name=”catalogId” data=”${catalogId}” />
</wcf:getData>

<c:set var=”catalogEntry” value=”${catalogNavigationView.catalogEntryView[0]}” />
<%@ include file=”CatalogEntryPriceDisplay.jspf” %>

Then getting list price and offer price is a lot more cleaner in the CatalogEntryPriceDisplay.jspf

<c:forEach var=”price” items=”${catalogEntry.price}” >
<c:choose>
<c:when test=”${price.priceUsage == ‘Display’}”>
<c:set var=”displayPrice” value=”${price.value.value}” />
<c:set var=”listPriced” value=”true”/>
</c:when>
<c:when test=”${price.priceUsage == ‘Offer’}”>
<c:set var=”calculatedPrice” value=”${price}” />
<c:set var=”checkNumberOfApplicableContractIds” value=”true”/>
</c:when>
</c:choose>
</c:forEach>

And the same for the attachments management

C:\IBM\WCDE_ENT70\components\store-enhancements\samples\SOACatalogStorefrontServices\stores\Madisons\Snippets\Catalog\CatalogEntryDisplay\AttachmentImagesDisplay.jspf

<c:set var=”catEntry” value=”${catalogNavigationView.catalogEntryView[0]}” />

<c:set var=”catalogEntryDetails” value=”${catEntry}” scope=”request” />

<c:set var=”catEntry” value=”${catalogEntryDetails}” />

<c:set var=”attachments” value=”${catEntry.attachments}” />

so you can directly specify

<c:forEach items=”${attachments}” var=”attachment”>
<c:if test=”${‘IMAGE_SIZE_40′ == attachment.usage}”>
<c:set var=”image40Attachment” value=”${attachment}” />
</c:if>…

and

<c:choose>
<c:when test=”${!empty image40Attachment}”>
<c:set var=”productCompareImagePath” value=”${staticAssetContextRoot}/${image40Attachment.attachmentAssetPath}” />
</c:when>…

without instantiate any other databean object.

Older Posts »

Categories

Follow

Get every new post delivered to your Inbox.

Join 77 other followers

%d bloggers like this: