Wednesday, July 7, 2010

Implementing Stackable product promotions site wide

Out of the box, product promotions can not be stacked, which means only 1 product promotion per item.
Production promotions can be stacked with the following configuration and updates in database. I would strongly recommend testing all different kind of custom and out of box promotions.

Step1 disable the policy 'Product: Any order item can only participate in one promotion' from px_policy

Disabling the policy lets multiple product promotions be evaluated, otherwise just the one with the highest priority goes in (or in the case of equal priorities, whichever happened to be evaluated first.)

update px_policy set status=1 where px_policy_id in (select px_policy_id from px_policy where name like 'Product: Any order item can only participate in one promotion')

update px_policy set xmlparam=replace(xmlparam,'Active','Inactive') where px_policy_id in (select px_policy_id from px_policy wherename like 'Product: Any order item can only participate in one promotion')

Step2: Modify WCSPromotionEnginConfig.xml

Modifying the XML lets promotions stack, instead of just evaluating all of them, and picking the best one.

In the WCSPromotionEngineConfig.xml, you have to disable the behavior true to false This change will allow all the price adjustment based on discounted price (or contract price displayed in the shopcart).

Step3: Update all promtions from accelerator. If you want this to affect your exisiting promotions.

you have to update all the promotions ( don't need to change anything, but need to resave the promotion in order to get promotion XML updated). After that, all the promotions for the same product can be combined.

Saturday, July 3, 2010

Business Auditing feature in WCS

IBM websphere commerce uses : WebSphere Commerce uses the industry standard Triple DES (data encryption standard)

This ensures that a third party using network-sniffing programs cannot snoop on the network when a user submits a password.
Passwords are never decrypted during the authentication process, as is the common security practice.
All user passwords are one-way hashed using the SHA-1 hashing scheme and encrypted using a 128-bit key based on the merchant key.


Business Auditing:

Business auditing is the capturing of the business logic and objects during a WebSphere Commerce operation.A report on business auditing is available in the Administration Console.

WebSphere Commerce business auditing records the information about the execution of business logic, such as the command, request, response, command context, and other information. For example, if a Customer Service Representative overrides a price for a particular ordered item within an order, this needs to be captured, and is useful to resolve any discrepancies between the price quoted to the customer and the customer's bill.

If an error occurs while executing any business logic, WebSphere Commerce attempts to execute the business logic, and this attempt is recorded to indicate that the request failed.

To use the business auditing feature, you must first enable it using Configuration Manager. By default, when you install WebSphere Commerce, the business auditing feature is already enabled. The WebSphere Commerce system captures the execution of specific business logic based on some default configuration. You can further customize which commands you want captured during a business audit (that is, enable existing or add new commands) by configuring the BusinessAuditDataCapture.xml file. The data captured by WebSphere Commerce system is stored in the BUSAUDIT table.


customization: BusinessAuditDataCapture.xml
enabling: For servers it is enabled using the configuration manager

Adding custom commands:
<AuditCommand eventType="MBR" command="com.custom.commands.CustomActivityControllerCmd" audit="true"/>
<AuditCommand eventType="MBR" command="com.custom.commands.CustomOrderSearchControllerCmd" audit="true"/>

Commerce where can I find?

This information below is for WCS 6.0

Accelerator:
https://localhost:8000/webapp/wcs/tools/servlet/ToolsLogon?XMLFile=common.mcLogon&storeId=0

Admin Console:
https://localhost:8002/webapp/wcs/admin/servlet/ToolsLogon?XMLFile=adminconsole.AdminConsoleLogon&storeId=0

Org Admin Console:
https://localhost:8004/webapp/wcs/orgadmin/servlet/ToolsLogon?XMLFile=buyerconsole.BuyAdminConsoleLogon&storeId=0

Dynacache:
https://localhost:8002/cachemonitor/

Nifstack.xml:
\properties\version\update\backup
/opt/IBM/WebSphere/CommerceServer60/properties/version/update/backup/NIFStack.xml

wc-server.xml:

\xml\config\wc-server.xml
WC_LIVE_CELL and WC_LIVE would need to be replaced with the node name.
/opt/IBM/WebSphere/AppServer/profiles/LIVE/installedApps/WC_LIVE_cell/WC_LIVE.ear/xml/config



Temp folder:
\wasprofile\temp
/opt/IBM/WebSphere/AppServer/profiles/LIVE

Logs:
\wasprofile\logs
LIVE and WC_SS_LIVE_1 need to be replaced with appropriate instance names.
/opt/IBM/WebSphere/AppServer/profiles/LIVE/logs/WC_SS_LIVE_1


Tracing:
log into wasconsole
https://hostname:9043/ibm/console
or
Toolkit, right click on the server->goto admin console.

Application servers > Change Log Detail Levels
e.g. after changes done to enable WC_SERVER
*=info:enable.trace.log.*=all:com.ibm.websphere.commerce.WC_USER=all:
com.ibm.websphere.commerce.WC_SERVER=all:
com.ibm.websphere.commerce.WC_ACCESSCONTROL=all

Regular Expressions in Java\WCS Examples

REGEX 101:
Regular expressions are a powerful (and fairly standardized) way of searching, replacing, and parsing text with complex patterns of characters.

. is a wild character
e.g b.t in text could search bat bit bet bot b*t b t

[] search to Limit to a range of characters.

e.g. b[aeio]t : bat bet bit bot

() search more than 1 characters. (can not use [] to search more than 1 character)
e.g. b(a|e|i|o|oo)t : bat bet bit bot boot

* 0 or more times
+ 1 or more times
? 0 or 1 time
{n} Exactly n number of times
{n,m} n to m number of times
- Indicates a range that would match any number\character.
\ used for escaping regexp special characters.
"^" notation is also called the NOT notation. If used in brackets, "^" indicates the character you don't want to match.
\s Search spaces and tabs.
Simpler short cuts:
\d [0-9]
\D [^0-9]
\w [A-Z0-9]
\W [^A-Z0-9]
\s [ \t\n\r\f]
\S [^ \t\n\r\f]

e.g. US telephone number 858-343-1111
Regexp expression to be used: [0-9]{3}\-[0-9]{3}\-[0-9]{4}

If - is optional: 8583431111
Regexp expression to be used: [0-9]{3}\-?[0-9]{3}\-?[0-9]{4}

e.g. 8836KV [0-9]{4} [A-Z]{2}
(first 4 numbers)(last 2 characters.)

e.g. May 11, 2010 : [A-Z]\s+[0-90{1,2},\s*[0-9]{4}
[A-Z]+(first 3 characters)\s+(mandatory space),\s* (0 or more spaces)[0-9]{4}

E.g. These examples are with JDK 1.4.2 API.

import java.util.regex.Matcher;
import java.util.regex.Pattern;

Pattern class:

An instance of the Pattern class represents a regular expression that is specified in string form in a syntax similar to that used by Perl.

A regular expression, specified as a string, must first be compiled into an instance of the Pattern class. The resulting pattern is used to create a Matcher object that matches arbitrary character sequences against the regular expression. Many matchers can share the same pattern because it is stateless.

The compile method compiles the given regular expression into a pattern, then the matcher method creates a matcher that will match the given input against this pattern. The pattern method returns the regular expression from which this pattern was compiled

Matcher Class

Instances of the Matcher class are used to match character sequences against a given string sequence pattern. Input is provided to matchers using the CharSequence interface to support matching against characters from a wide variety of input sources.

A matcher is created from a pattern by invoking the pattern's matcher method. Once created, a matcher can be used to perform three different kinds of match operations:

  • The matches method attempts to match the entire input sequence against the pattern.
  • The lookingAt method attempts to match the input sequence, starting at the beginning, against the pattern.
  • The find method scans the input sequence looking for the next sequence that matches the pattern.

Each of these methods returns a boolean indicating success or failure. More information about a successful match can be obtained by querying the state of the matcher.

This class also defines methods for replacing matched sequences by new strings whose contents can, if desired, be computed from the match result.

The appendReplacement method appends everything up to the next match and the replacement for that match. The appendTail appends the strings at the end, after the last match.


Sample methods :



public static String removeDuplicateWhitespace(String inputStr) {
String patternStr = "\\s+";
String replaceStr = " ";
Pattern pattern = Pattern.compile(patternStr);
Matcher matcher = pattern.matcher(inputStr);
return matcher.replaceAll(replaceStr);
}


public static String replaceSpecialCharsWithHTMLTags(Map splCharsMap, String patternStr, String input)
{
final String METHODNAME ="replaceSpecialCharsWithHTMLTags";

Pattern r = Pattern.compile(patternStr, Pattern.CASE_INSENSITIVE);
Matcher m = r.matcher(input);

m.reset();
StringBuffer sb = new StringBuffer();
String replaceStr = null;
String supTagElement = null;

while (m.find())
{
supTagElement = input.substring(m.start(), m.end());

if (splCharsMap.containsKey(supTagElement))
{
replaceStr = (String) splCharsMap.get(supTagElement);
}

if ( replaceStr!=null && replaceStr.length > 0 )
m.appendReplacement(sb, replaceStr);
else
m.appendReplacement(sb, supTagElement);
}

m.appendTail(sb);
return sb.toString();
}

WCS:

There is application for regular expression in both for front validation JSP validation for feeds and also during string search\replace in the back end.



Ref:
http://java.sun.com/developer/technicalArticles/releases/1.4regex/

Monday, June 21, 2010

Testing with Rspec, Cucumber, Selenium, Watir & Buzz around BDD, TDD

I was lucky to be working with some folks this past week, who are working on a bleeding edge commerce framework and this particular blog is more on the testing frameworks for front end.

I will soon have an article on building a front end store using ROR for Websphere commerce and it will be really useful to automate the test scripts using RSpec and one of the automation tools out there.

This is meant to be 101 for these concepts and I have added links below for deep diving.

BDD and TDD are paradigms essentially bringing the prominence of writing test cases before development and also making it easier on non coders to understand the test cases.

TDD: Test driven development
1. Writing automated test scripts before actually starting to write codes.
2. It is a great idea using any programming language but traditionally development with languages such as Java was pretty high hence it was skipped as the larger development life cycle was blamed for it.
But It makes great sense for using this approach for ROR (Ruby).
3. Test driven development brings lot of clarity to the design in the very early stage of the development cycle.

e.g.

BDD: Behavior Driven Development
1. It extends the concept of the TDD and takes it one level further as it makes writing test scripts in a very expressive way and no programmatic way.
2. It really helps non programmers (BA, QA, PM) to understand the test cases as they are expressed in a simple English like language.
3. Using 'should' when describing the behavior of software to help clarify responsibility and questioning the requirements.
4. Using 'ensure' when describing responsibilities of software to differentiate outcomes in the scope of the code in question from side-effects of other elements of code.
5. Using mocks to stand-in for collaborating modules of code essentially stubbed out without the actual implementation.

e.g. RSPec, Cucumber

Selenium: Selenium IDE and Selenium RC. (Remote Control)

Selenium IDE provides automated way of recoding tests from a Firefox plug in and it has a powerful feature to validate tests by providing several commands to assert the results. It also provides a powerful mechanism to export the test case into a programming language such as Java, Ruby (RSpec),Perl, .etc.

Selenium RC: is a tool that allows you to launch browser sessions and run Selenium tests against those browsers.
To do this, the Selenium RC server acts as an intercepting proxy for the browser

Selenium-IDE does not directly support:

* condition statements
* iteration
* logging and reporting of test results
* error handling, particularly unexpected errors
* database testing
* test case grouping
* re-execution of failed tests
* test case dependency
* screenshot capture of test failures

Flash is not supported as a part of the Selenium-IDE but there is a flash extension for Selenium Flash and it also requires changing the actual Flash action scripts to add methods to be called from Selenium. It is not a very good practice.

The results from the tests can be verified by connecting from the database.

Watir: Watir is automated testing framework. It does not have a IDE of it's own but there is a testwide recorder that can be used. A combination of RSpec and Watir really makes very readable test scripts. It offers Flash support on firefox but I could not find a lot of documentation around this. So I have my doubt's around automating Flash components.

Cucumber is designed to allow you to execute automated integration tests. It is a tool for implementing Behavior Driven Development.It can work in Conjecture with Rspec.

Each feature is expressed as a Give\When\Then

Given: Preconditions to be filled.
When: This section defines what feature does (i.e., the behaviour, the steps).
Then: Testable out come that can be validated.


http://www.oreillynet.com/pub/a/ruby/2007/08/09/behavior-driven-development-using-ruby-part-1.html
http://www.ibm.com/developerworks/web/library/wa-rspec/
http://wiki.openqa.org/download/attachments/400/Selenium+IDE.swf?version=1
http://www.rubyinside.com/cucumber-the-latest-in-ruby-testing-1342.html

Thursday, June 17, 2010

Character Encoding and Commerce

Character Encoding 101:

The "charset" parameter identifies a character encoding, which is a method of converting a sequence of bytes into a sequence of characters. This conversion fits naturally with the scheme of Web activity: servers send HTML documents to user agents as a stream of bytes; user agents interpret them as a sequence of characters. The conversion method can range from simple one-to-one correspondence to complex switching schemes or algorithms...

Reference: Section 5.2 Character encodings of the HTML Document Representation W3C Recommendations

Character encoding tells the browser and validator what set of characters to use when converting the bits to characters.

Types: what does this mean, there are different standards of character set encoding
You see various encoding types

Traditional ASCII is 7 bits and has limited character representation.
encoding="ISO-8859-1"
encoding="windows-1252
encoding="utf-8"

Even though UTF-8 is one of the most popular some of the old browsers might not support hence we used to use ISO-8859-1 encoding in some pages.

windows-1252 :
Windows-1252 is a character encoding of the Latin alphabet, used by default in the legacy components of Microsoft Windows in English and some other Western languages
ISO-8859-1 :
UTF-8,UTF-16,UTF-32 :
Unicode is an international character set standard which supports all of the major scripts of the world, as well as common technical symbols.
Unicode transformation unit and each character is store in 21-bits so depending on each of these UTF types it is stored as a multiple of 8 bytes
e.g. UTF-8 , it could be saved in upto 4 bytes.


Developers:

Java:
In the Java programming language char values represent Unicode characters. Unicode is a 16-bit character encoding that supports the world's major language
UTF-16 (Java).

In WCS:

The language table has a ENCODING column that specifies the encoding for language
e.g.

select encoding from language where language_id=-1;

From end in JSP:
Character encoding

We set the character encoding to UTF-8 as this is what is present in the DB for language encoding.

<%
response.setContentType("text/xml");
response.setCharacterEncoding("UTF-8");
response.setHeader("Cache-Control","max-age=0");
%>


Form Submit: In commerce what ever is specified in front end should match with what ever is specified in the encoding attribute of the language table.

select encoding from language where language_id= language passed in the command context.

Database:
e.g. If you need the character encoding to windows 1252, you can do that in the session while executing SQL statements.

set NLS_LANG=AMERICAN_AMERICA.WE8MSWIN1252

Database Client:

I use today and for the client to show the correct characterset, we have modified.

HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE\Key_OraClient...
Change “NLS_LANG” to AMERICAN_AMERICA.UTF8




Good reference URLs:
http://java.sun.com/javase/technologies/core/basic/intl/faq.jsp
http://java.sun.com/docs/books/tutorial/i18n/text/convertintro.html
http://tlt.its.psu.edu/suggestions/international/web/codehtml.html

Sunday, March 7, 2010

JSP Error Handling and Extending OOB framework

Out of the box these 2 are good Articles:

http://publib.boulder.ibm.com/infocenter/wchelp/v6r0m0/topic/com.ibm.commerce.developer.doc/concepts/csdcommanderror.htm

http://publib.boulder.ibm.com/infocenter/wchelp/v6r0m0/topic/com.ibm.commerce.developer.doc/concepts/csdjsperror.htm

Essentially there are following elements:
1. ECSystemException and ECApplicationException classes, that are used to throw exceptions from inside the controller.
2. Extending the ECMessage and ECMessageKey
3. The errors are intercepted by the ExtStoreErrorDataBean and mapped to resource bundles
4. Errors are displayed in JSP.

Define the property in ExtMessages_en_CA.properties (
_ERR_RESTRICTED_PROD = This item is restricted for delivery.


Extending ECMessage and ECMessageKey:

public interface EXTMessageKey extends ECMessageKey{
public static final String _ERR_RESTRICTED_PROD = "_ERR_RESTRICTED_PROD";

public static final String _ERR_MAX_NUM_OF_OF_CARTS_REACHED = "_ERR_MAX_NUM_OF_OF_CARTS_REACHED";

}

public class EXTMessage extends ECMessage{
//this file structure needs to be created inside toolkit properties folder
for com/ext/common/messages/EXTMessages.propertie

public final static String EXT_MESSAGES_RESOURCE_BUNDLE = "com.ext.common.messages.EXTMessages";

// final constants
public static final int USER = ECMessageType.USER;
public static final int SYSTEM = ECMessageType.SYSTEM;

// message severities
public static final long ERROR = ECMessageSeverity.ERROR;
public static final long WARNING = ECMessageSeverity.WARNING;
public static final long STATUS = ECMessageSeverity.STATUS;
public static final long INFO = ECMessageSeverity.INFO;

public EXTMessage(long msgSeverity, int msgType, String msgKey)
{
super(msgSeverity, msgType, msgKey, EXT_MESSAGES_RESOURCE_BUNDLE);
}

//system
public static final EXTMessage _ERR_MAX_NUM_OF_OF_CARTS_REACHED = new EXTMessage(ERROR, SYSTEM, EXTMessageKey._ERR_MAX_NUM_OF_OF_CARTS_REACHED);

public static final EXTMessage _ERR_PROCESSING_REQUEST = new EXTMessage(ERROR, SYSTEM, EXTMessageKey._ERR_PROCESSING_REQUEST);

//user
public static final EXTMessage _ERR_LOGIDPWDPSID_NOT_PRESENT = new EXTMessage(ERROR, USER, EXTMessageKey._ERR_LOGIDPWDPSID_NOT_PRESENT);

public static final EXTMessage _ERR_RESTRICTED_PROD = new EXTMessage(ERROR, USER, EXTMessageKey._ERR_RESTRICTED_PROD);
}


In the controller command, The error needs to be thrown as an exception for example:

throw new ExtendedApplicationException( EXTMessage._ERR_RESTRICTED_PROD,
CLASSNAME,
METHOD_NAME,
ORDER_SHOP_CART_VIEW,
true);