December 2007


Since I am no longer using Perforce I wanted to turn off the Windows Explorer because somethings I would accidentally select the Perforce option in the right click menu and it would hang for a long time as it tried to reach the Perforce server.

This blog article says that the simplest way to do this is to select Change/Remove Perforce P4Win Components from the Add or Remove Programs Control Panel and then select the Windows Explorer integration for uninstall. When it is done uninstalling a reboot is required.

Another possibly simpler way is to:

  1. right click any folder
  2. choose Perforce > Options
  3. uncheck all check boxes

Subversion branching and tagging is basically copying from one repository directory to another.

This article gives great instructions on how to branch and tag with subversion. This article is also good.

To compare branches you can simply do something like this svn diff [path] [path]. For example svn diff http://foo.com/branches/stable http://foo.com/trunk.

To merge from a branch to the trunk you can use svn merge like this. Note that you need to have the trunk checked

$ cd trunk
$ svn merge -r 3:4 svn+ssh://fkim@betweengo.com/home/fkim/svn/foo/branches/stable/doc/html doc/html

I wanted to do some shell processing on the contents of a directory. To do this I needed to put the contents of the directory in an array. Fortunately this is not difficult with bash.

  1. First capture the output.

    ls_output=$(ls /images)

  2. Next declare an array and reference the output with this array.

    declare -a img_files
    img_files=($ls_output)

  3. Now you can access the array directly or loop through it.

    echo ${img_files[0]}
    for img_file in ${img_files[@]}
    do
      ...
    done

Thanks O’Reilly’s Bash Cookbook.

I was counting how many times a file was referenced by other files. I then wanted to do some processing based on this number.

To do this I saved the output of this count in a variable which I was then able to reference later in the shell script.

num_files=`find . -type f -name '*.html' | xargs grep $img_file | wc -l`

# delete this file if it is not referenced
if [ "0" = $num_files ]
then
  rm $IMAGE_DIR/$img_file
fi

When troubleshooting orders it is really helpful to be able to view the order in the ACC.

By default orders are saved because persistOrders property of the /atg/commerce/ShoppingCart component is set to true. If you don’t see incomplete orders being saved then this means this property is not set to true.

More information on Troubleshooting Order Problems can be found in the ATG Commerce Programming Guide.

When starting ATG instances with the DCS module I will often see this warning.

DistributorSender No remote servers configured

This is because in the product catalog two item descriptors, media-internal-binary and media-internal-text, are configured to use the Dynamo content distributor system if it is available. This is documented in the Using Content Distribution with a SQL Content Repository section of the ATG Dynamo Programming Guide.

Since out of the box the Dynamo content distributor system is not configured we see the above warning. To turn it off simply set loggingWarning=false for the /atg/commerce/catalog/ContentDistributorPool component.

In many ATG instances I will see this warning upon startup.

/atg/dynamo/service/ClientLockManager The useLockServer property of: /atg/dynamo/service/ClientLockManager is false and so global locking is disabled

As explained in the Enable the Repository Cache Lock Managers section of the Installation and Configuration Guide for DAS the ClientLockManager must be enabled if you are using locked mode caching anywhere in your SQL repository, which is typically the case in production when you are running more than one ATG server. The above warning is to inform the ATG administrator that currently the ClientLockManager is not enabled.

To enable it follow the instructions in the Configuring Lock Managers subsection of the Locked Caching section of the ATG Repository Guide.

On a single ATG instance environment you might still choose to setup the ClientLockManager and ServerLockManager just to get rid of this warning. To do this do the following.

  1. Enable ClientLockManager by creating localconfig/atg/dynamo/service/ClientLockManager.properties.lockServerAddress=localhost
    lockServerPort=9010
    useLockServer=true
  2. Start ServerLockManager by adding it to localconfig/atg/dynamo/service/Initial.properties.initialServices+=ServerLockManager

After doing this though you’ll see a warning like this.

/atg/dynamo/service/ServerLockManager No backup server is configured for Lock ServerCRAPBOOK-PRO/localhost:9010 It becomes Primary Server

So maybe in the end it’s better just to ignore the ClientLockManager warning, maybe even disable it. :-)

Today I was using the CategoryLookup droplet to find a category’s child products. However when I accessed the child products I would get this JDBC error.

java.lang.NullPointerException
at java.lang.String.(String.java:166)
at oracle.sql.CharacterSet.AL32UTF8ToString(CharacterSet.java:1517)

I realized my product data was corrupted. However this category had over 70 child products. The stack trace wasn’t telling me which one was corrupt and going through each child product to find out which one was corrupt was too painful.

I first queried the database to find all the child product ID’s.

SQL> select child_prd_id from dcs_cat_chldprd where category_id='cat101' order by sequence_num;

I then created a simple JHTML page which would query each child product and output which ones were corrupted.

<java>
final String [] product_ids = { “prod101″, “prod102″, “prod103″ };

for (int ii = 0; ii < product_ids.length; ii++) {
out.print(ii + ". [" + product_ids[ii] + “] “);
try {
</java>
<droplet name="/atg/commerce/catalog/ProductLookup">
<param name="id" value="`product_ids[ii]`”>
<oparam name="output">
<valueof param="element.displayName"/><br/>
</oparam>
</droplet>
<java>
} catch (RuntimeException exc) {
out.println(exc + "<br>");
}
}
</java>

Once I knew which child products were bad I removed their mappings to the category in dcs_cat_chldprd.

SQL> delete from dcs_cat_childprd where child_prd_id = 'prod102' and category_id='cat101';

Then I updated the sequence numbers so that they are all consecutive by moving the ones at the end to fill the holes created by the previous deletes.

SQL> update dcs_cat_childprd set sequence_num = 1 where child_prd_id = 'prod103' and category_id='cat101';

ATG’s promotion engine is pretty advanced and relatively easy to use for creating promotions as described in their Creating Promotions section in the Commerce Programming Guide.

ATG’s documentation gives numerous examples of how to create buy N get M free promotions.

For example to create a simple Buy 2 Get 1 Free promotion one would create the following rule.

“For next 2 items whose product is in the category named Foo, discount up to 1 item whose product is in the category named Foo”

The only issue with the above rule is that you cannot set conditions on customer’s. If you need to set conditions on customer’s then you have create a rule like this.

“When order contains at least 3 items whose product is in the category named Foo and at most 5 items whose product is in the category named Foo and customer’s name is Frank, discount up to 1 item whose product is in the category named Foo”

Note you will have to create separate promotions for each level, i.e. one for the 3 for 1, one for the 6 for 2, one for the 9 for 3, etc.

Also if you change a promotion I believe you have to restart the ATG server otherwise at least the current customers will still be using the old promotion.

Sometimes I am faced with a situation where I need to know the source for a view or a procedure or a function. Fortunately Oracle stores the source in the database.

First I check to see what kind of object whose source I need is.

SQL> select object_name,object_type,status from user_objects where object_name = 'FOO';

If the object is a table I can simply recreate the table by doing a desc on that object.

SQL> desc FOO;

If the object is a function or stored procedure you can find its source in the user_source table.

SQL> select text from user_source where name = 'FOO' order by line;

If the object is a view you can find its source in the user_views table.

SQL> select text from user_views where view_name = 'FOO';

If the output seems to be truncated it is because text is of type LONG which is a big binary field. To allow more output do this.

SQL> set long 4000

Thanks to this article and this forum for helping me figure this out.

Next Page »