Automating Setup of ATG Content Admin

When setting up ATG Content Admin for the first time one of the first steps to follow is to import a deployment topology and initialize with a first deployment. This is so that you are able to initialize deployments.

Both steps can be automated.

To import a deployment topology automatically we can set importAndInitializeTopologyOnStartup on the /atg/epub/DeploymentServer component to true and then specify deployment topology file on the topologyDefinitionFile property in the same component.

#/atg/epub/DeploymentServer
importAndInitializeTopologyOnStartup=true
topologyDefinitionFile=/atg/epub/deploymentTopology.xml

To automate the initial deployment some custom java code is required using the public methods in the DeploymentServer component.

Excluding unwanted SKUs from Endeca

When using the ATG-Endeca Integration it is simple and clear how to filter out products from Endeca but not so obvious how to filter out SKUs from the index.

Suppose that your data model has more than one sub-type of SKU and that each product’s childSKU property contains more than one sub-type of SKU. Here are the steps required to only index the SKU types that you want:

  1. Create a separate indexed items group for the childSKUs property. You can then reference the indexed items group in the product-sku-output-config.xml
    <item property-name="childSKUs" repository-item-group="/component/path/SpecificSkusIndexedItemGroups">
        ...
    </item>
  2.  

  3. Create the SpecificSkusIndexedItemsGroup component
    SpecificSkusIndexedItemsGroup<
    $basedOn=/atg/commerce/search/IndexedItemsGroup 
    # The name of the RepositoryItemGroup 
    groupName=Specific Skus Indexed Items Group 
    # The product item-descriptor name 
    repositoryViewName=sku 
    # The RuleSet that defines the set of items to be indexed. 
    rules= <ruleset> <accepts> <rule op=eq> <valueof target="type"> <valueof constant="someSkuType"> </rule> </accepts> </ruleset>
  4. Restart and do a baseline using the ProductCatalogSimpleIndexingAdmin component

 
You should now have only the SKUs that you want in the index. Enjoy.

The beauty of Scala case classes

One of my favorite features in Scala are case classes. Below is an example of the declaration of a case class:

case class Student(name:String, age:Int)

The declaration looks pretty simple, isn’t it?

Now let’s do it the java way:

public class Student {
  private String name;
  private int age;

  public Student(String name, int age) {
     this.name = name;
     this.age = age;
  }

  public String getName() {
    return this.name;
  }

  public String setName(String name) {
     this.name = name;
  }

  public int getAge() {
    return this.age;
  }

  public void setAge(int age) {
    this.age = age;
  }

  public boolean equals(Object obj) {
    ...
  }

  public int hashCode() {
    ...
  }

  public String toString() {
    ...
  }

Which method do you prefer.
Scala case classes are extremely powerful and their main use is not limited to writing abbreviated java beans.

By declaring a case class we get for free the equals, toString and hashCode methods. Nice, can it get any better? Yes….
You can easily create instances of a case class without having to declare a constructor and no need to use the new keyword:

val students = List(Student("John", 20), Student("David", 21))

Case classes are used for pattern matching. Pattern matching is similar to Java switch statements however it is many times more powerful. The example below shows a typical use for case classes with pattern matching:

abstract class Expression
case class Sum(a1:Int, a2:Int) extends Expression
case class Diff(a1:Int, a2:Int) extends Expression
case class Mult(a1:Int, a2:Int) extends Expression

def doOperation(expr:Expression):Int = expr matches {
  case Sum(a1, a2) => a1 + a2
  case Diff(a1, a2) => a1 - a2
  case Mult(a1, a2) => a1 * a2
}

Adding methods to any class using Scala implicit class

Scala has many useful features – but one of the most useful is the ability to add any method to any class.

I will start with an example from the ATG world as this is a concrete example for me where this facility is extremely useful.
Let’s say you want to add a method called valideBespoke() to GenericFormHandler so that it can be used by any of your bespoke form handlers. Assuming that all the form handlers extend GenericFormHandler, all you need to do is, to create another class BetterGenericFormHandler class which extends GenericFormHandler. Then change all the bespoke formhandlers to extend this class. At this point you can use the method validateBespoke().

However this approach will not work if you extend existing ATG form handlers which in turn extend the origin GenericFormHandler class.

In Scala the solution to this problem is to use implicit classes. An implicit class wraps an existing class and allows an addition of any number of methods. It only works for new methods – not for overriding existing methods.
But still pretty useful. See an example below:

  class GenericFormHandler {
    def originalDoSomething(): String = {
      "this is the original method"
    }
  }
  implicit class BetterGenericFormHandler(frh: GenericFormHandler) {
    def validateMethod(): Boolean = {
      true
    }

    def originalDoSomething(): String = {
      "this is the better method"
    }
  }

  class CustomGenericFormHandler extends GenericFormHandler {
    def doSomething(): Boolean = {
      this.validateMethod
      // do more stuff
    }
  }

There are only a few restrictions:

  • An implicit class needs to be defined inside another class
  • The implicit class only can take one non-implicit argument
  • The implicit class name should not clash with the name of a method, member or object in scope.
  • You need to import the implicit class definition where you need to use it It would be nice if it worked without imports, but it doesn’t. Still a small price to pay.
  • It does not allow to override existing methods in the class.

Please see the following link for more details about implicit classes in Scala:

Note that to solve the problem above you don’t need to use implicit classes. In Scala, a Trait allows to define a method with a body. As long as your custom form handler uses that Trait, in the same way you can access the validateMethod().

How to delete an .svn folder from all subdirectories

It is very easy to make mistakes when using subversion and trying to copy folders to different locations. Any .svn directories in the wrong place will have unexpected consequences. This is how you can delete all .svn directories recursively on your macos or linux system:

find . -name .svn -exec rm -rf {} ;

How to use the Cache Droplet in Oracle ATG to improve performance

The main page of a typical ATG Commerce Website often has many targeters and other rich content which is computer-resource intensive.
Often, the easiest way to speed up the load time of a home page is to wrap any targeters within a
Cache droplet:

<dsp:droplet name="/atg/dynamo/droplet/Cache">
<dsp:param name="key" value="${category.repositoryId}_${userLocale}"/>
<dsp:oparam name="output">
....
</dsp:oparam>
</dsp:droplet>

The key parameter needs to be sufficiently unique. For example if your home page has a version for each locale then a key should be part of the cache key.

The following caveats apply:

1. Ideally, no personalization rules should exist in the targeters. I.e. targeter rules should apply to all users.
2. Using the cache droplet increases the memory usage of the application.
3. Any deployment from CA will invalidate all the items in the cache droplet. This means that after a deployment, the home page load times will sharply increase.
4. Product availability changes will not be visible in the home page until the cache entry expires.

The following properties control the behavior of the cache:

cacheCheckSeconds – the number of seconds which an entry in the cache takes to expire
purgeCacheSeconds – the number of seconds for the whole cache content to be purged

How to create private/public ssh keys in Linux

If you want to use ssh to access different servers in your network but you don’t want to always type your password, then follow these steps:

ssh-keygen -b 2048 -t rsa -f ~/.ssh/id_rsa

Now copy your public ssh key to the server you want to access remotely:

Example: scp ~/.ssh/id_rsa.pub :/tmp/

Now login to the server and add the id_rsa.pub key to ~/.ssh/authorized_keys

cat /tmp/id_rsa.pub >> ~/.ssh/authorized_keys
rm /tmp/id_rsa.pub

How to read from a text file in Java

There are several ways to read a text file in Java. Here is one of them:

try {
	        FileInputStream stream = new FileInputStream(file);
	        InputStreamReader reader= new InputStreamReader(stream);
	        BufferedReader breader = new BufferedReader(reader);
	        String line = null;
	        while ((line = breader.readLine())!= null) {
	           processLine(line);
	        }
	    }
	    catch (FileNotFoundException ex) {
	        ex.printStackTrace();
	    } catch (IOException e) {
            e.printStackTrace();
        }

Integrating ATG with Adobe Flex using BlazeDS

I have had a few inquiries about whether it is possible to integrate Adobe Flex with ATG via AMF. My short answer is Yes. It should be possible. The only issue that needs to be solved though is to access the nucleus components from flex. You need a factory for that e.g. the equivalent of ejbfactory(used for EJB 3) for ATG. At some stage when I have a bit of time in my hands I will create a factory for ATG Nucleus, if nobody creates one in the mean time.