Sunday, 1 March 2015

ATG Application Performance Tuning Toolkit




Here is list of tools I am using for application performance analysis and tuning.

 1.   JMeter : The Apache JMeter™ desktop application is open source software, a 100% pure Java application designed to load test functional behavior and measure performance. Apache JMeter may be used to test performance both on static and dynamic resources (Files, Web dynamic languages - PHP, Java, ASP.NET, etc. -, Java Objects, Data Bases and Queries, FTP Servers and more). It can be used to simulate a heavy load on a server, group of servers, network or object to test its strength or to analyze overall performance under different load types. You can use it to make a graphical analysis of performance or to test your server/script/object behavior under heavy concurrent load. 

2.   JvisualVM (Java VisualVM) :  Java VisualVM can be used by Java application developers to troubleshoot applications and to monitor and improve the applications' performance. Java VisualVM can allow developers to generate and analyse heap dumps, track down memory leaks, browse the platform's MBeans and perform operations on those MBeans, perform and monitor garbage collection, and perform lightweight memory and CPU profiling.

3.   TDA - Thread Dump Analyzer : The TDA Thread Dump Analyzer for Java is a small Swing GUI for analyzing Thread Dumps and Heap Information generated by the Sun Java VM.  
 
4.   MAT - Eclipse Memory Analyzer : The Eclipse Memory Analyzer is a fast and feature-rich Java heap analyzer that helps you find memory leaks and reduce memory consumption. Use the Memory Analyzer to analyze productive heap dumps with hundreds of millions of objects, quickly calculate the retained sizes of objects, see who is preventing the Garbage Collector from collecting objects, run a report to automatically extract leak suspects.

5.  Automatic Workload Repository (AWR) in Oracle Database : The Automatic Workload Repository (AWR) collects, processes, and maintains performance statistics for problem detection and self-tuning purposes. This data is both in memory and stored in the database.

The statistics collected and processed by AWR include :
  • Object statistics that determine both access and usage statistics of database segments.
  • Time model statistics based on time usage for activities, displayed in the V$SYS_TIME_MODEL and V$SESS_TIME_MODEL views.
  • Some of the system and session statistics collected in the V$SYSSTAT and V$SESSTAT views SQL statements that are producing the highest load on the system, based on criteria such as elapsed time and CPU time.
  • ASH statistics, representing the history of recent sessions activity.
I will update more on performance tuning.....

Friday, 27 February 2015

ATG Datasource Debugging / Print SQL statements for repository queries

Here are the steps to debug Data-source problems.

1.    Datasource Debugging on WebLogic or WebSphere.

To add datasource debugging, first rename the datasource used by your applications (usually JTDataSource,properties). Then create a new JTDataSource.properties file with the following contents:
$class=atg.service.jdbc.WatcherDataSource
dataSource=/atg/dynamo/service/jdbc/DirectJTDataSource
showOpenConnectionsInAdmin=false
logDebugStacktrace=false
loggingDebug=false
monitored=false
loggingSQLError=true
loggingSQLWarning=false
loggingSQLInfo=false
loggingSQLDebug=false 
Second, create a DirectJTDataSource.properties file with the following contents:
$class=atg.nucleus.JNDIReference
JNDIName=java:/ATGSolidDS 
Where ATGSolidDS is replaced by the JNDI name of your application server data source.
Place both properties files in your localconfig directory. To enable data source debugging, set the monitored property and the loggingSQLInfo property in the JTDataSource.properties file to true.

Note: Due to the potential performance impact, this feature should be used only in a development environment. Do not enable SQL debugging in a production site.

2.    Datasource Debugging on JBoss.

The default JTDataSource for JBoss allows you to monitor and log data source information for debugging purposes. It does this using the WatcherDataSource class. A WatcherDataSource “wraps” another data source, allowing debugging of the wrapped data source. For example:
/atg/dynamo/service/jdbc/JTDataSource.properties
$class=atg.service.jdbc.WatcherDataSource
# The actual underlying DataSource.
dataSource=/atg/dynamo/service/jdbc/DirectJTDataSource
Note: Due to the potential performance impact, the features described here should be used only for debugging in a development environment. Do not use datasource logging in a production environment unless absolutely necessary.
WatcherDataSource Configuration
The default WatcherDataSource configuration is:
showOpenConnectionsInAdmin=false
logDebugStacktrace=false
loggingDebug=false
monitored=false
loggingSQLError=true
loggingSQLWarning=false
loggingSQLInfo=false
loggingSQLDebug=false 
This default configuration logs the following information:
  • currentNumConnectionsOpen
  • maxConnectionsOpen
  • numGetCalls
  • averageGetTime
  • maxGetTime
  • numCloseCalls
  • averageCloseTime
  • maxCloseTime
  • averageOpenTime
  • maxOpenTime.
     
    For additional debugging information, you can set the following properties to true:
    • showOpenConnectionsInAdmin—Lists currently open connections, along with the amount of time they have been held open and the thread that is holding them open. This information is useful for identifying Connection leaks. If logDebugStacktrace is also true, then stacktraces are displayed as well.
      Note: This momentarily prevents connections from being obtained or returned from the DataSource, so severely affects performance.
    • loggingDebug—Logs debug messages on every getConnection() and close() call. These messages include interesting information such as sub-call time, number of open connections, and the calling thread. If logDebugStacktrace is also true then a stacktrace is logged as well.
    • logDebugStacktrace—Creates stacktraces on each getConnection() call. This allows the calling code to be easily identified, which can be useful when trying to find Connection leaks, code that is holding Connections open for too long, or code that is grabbing too many Connections at a time.
      Note: This is done by generating an exception, which affects performance.
    • monitored—Gathers additional connection statistics and SQL logging.



Saturday, 14 February 2015

MDEX Engine 6.4 language-specific, dictionary based, linguistic analysis features

Here is the list of new language specific features of  MDEX 6.4.

Segmentation The process of breaking up the non-whitespace language's text into meaningful units.
Tokenization The process of breaking a stream of text up into words, phrases, symbols, or other meaningful elements.
Orthographic normalization The creation of a standard indexed form for diacritic marks.
Decompounding The decomposition of compound word forms into their base terms.
Dynamic stemming The process of determining the base form of a word; a process based on dictionary entries and language specific rules.
Stop words A list of words to be ignored by the Endeca MDEX Engine. Sample stop word lists are now provided for each supported language.

Thursday, 5 February 2015

Update JSP files in compressed war file

Here are the steps to update jsp file in compressed war.
  1. Extract war and update the file as per your need.
  2. Open original war file using 7-zip tool.
  3. Navigate to file location in war (in 7-zip explorer).
  4. Drag the modified file in 7-zip.

Sunday, 11 January 2015

Customizing DeploymentEventListener

To confgiure a customized DeploymentEventListener, Here are the steps.
  1. Define a listener service class that implements the interface DeploymentEventListener and implement the method deploymentEvent(DeploymentEvent pEvent).
  2. Configure an instance in Nucleus on the appropriate server and register it with the DeploymentServer or DeploymentAgent as appropriate.
  • Configure the listener on the asset management server (BCC) and register it with the /atg/epub/DeploymentServer, so it listens for deployment events fired when the deployment changes its state.
  • Configure the listener on the target (production/stagging) server and register it with the local /atg/epub/DeploymentAgent, so it listens for deployment events fired when an agent changes its state.
Here is sample code to print the assets changed/modified in BCC project. Along with configuration. You can customize code as per your need.

Note : Custom is the custom module created for this customization.

1.   Custom listener class.
Path : /Custom/src/com/test/service/CustomDeploymentEventListener.java
File Content : 


package com.test.service;

import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;

import javax.ejb.EJBException;
import javax.ejb.FinderException;

import atg.deployment.common.event.DeploymentEvent;
import atg.deployment.common.event.DeploymentEventListener;
import atg.epub.project.Project;
import atg.epub.project.ProjectConstants;
import atg.epub.project.ProjectHome;
import atg.nucleus.GenericService;
import atg.repository.RepositoryException;
import atg.repository.RepositoryItem;
import atg.versionmanager.AssetVersion;
import atg.versionmanager.exceptions.VersionException;

public class CustomDeploymentEventListener extends GenericService implements DeploymentEventListener {
/**
* boolean to denote whether to listen the event or ignore it
*/
private boolean enabled;
@SuppressWarnings("unchecked")
@Override
public void deploymentEvent(DeploymentEvent pDeploymentevent) {
vlogDebug("Enter deploymentEvent method of CustomDeploymentEventListener");
if (isEnabled() && pDeploymentevent != null &&
                 DeploymentEvent.DEPLOYMENT_COMPLETE == pDeploymentevent.getNewState()) {

 String[] projectIds = pDeploymentevent.getDeploymentProjectIDs();
 Project project = null;
 Set workSpaceAssets = null;
 Set<RepositoryItem> repositoryItemsUpdated = new LinkedHashSet<RepositoryItem>();
 Iterator<AssetVersion> workspaceAssetsIterator = null;
 RepositoryItem repositoryItem = null;
 try {
    if (projectIds != null && projectIds.length >= 1) {
   ProjectHome home = ProjectConstants.getPersistentHomes().getProjectHome();
   try {
project = home.findById(projectIds[0]);
   } catch (EJBException ejbException) {
if (isLoggingError()) {
logError("Cannot find project with Id " + projectIds[0], ejbException);
}
   } catch (FinderException finderException) {
if (isLoggingError()) {
       logError("Cannot find project with Id " 
                                                    + projectIds[0], finderException);
}
   }
}
if (project != null) {
workSpaceAssets = project.getAssets();
}
if (workSpaceAssets != null) {
 workspaceAssetsIterator = (Iterator<AssetVersion>) workSpaceAssets.iterator();
}
if (workspaceAssetsIterator != null) {
while (workspaceAssetsIterator.hasNext()) {
AssetVersion assetVersion = workspaceAssetsIterator.next();
try {
if (assetVersion != null) {
repositoryItem = assetVersion.getRepositoryItem();                        repositoryItemsUpdated.add(repositoryItem);
}
} catch (RepositoryException repoExc) {
      vlogError("Repository Exception while accessing item " 
                                                                   + repositoryItem, repoExc);
}
}
}

if (!repositoryItemsUpdated.isEmpty()) {
//print updated items
printUpdatedItems(repositoryItemsUpdated);
}
} catch (VersionException versionExc) {
vlogError("Version exception occured while processing deployed project"
                                                               , versionExc);
}
 }
vlogDebug("Exit deploymentEvent method of CustomDeploymentEventListener");
         }
/**
* Method to print updated repository items
* @param repositoryItems
*/
private void printUpdatedItems(Set<RepositoryItem> repositoryItems) {
vlogDebug("Start :: printUpdatedItems(Set<RepositoryItem>)");
for (RepositoryItem repositoryItem : repositoryItems) {
System.out.println("Updated item is "+repositoryItem);
}
vlogDebug("End :: printUpdatedItems(Set<RepositoryItem>)");
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
}

2.   Custom listener component.
Path : /Custom/config/com/test/service/listener/CustomDeploymentEventListener.properties
File Content :
       $class=com.test.service.CustomDeploymentEventListener
       enabled=true

3.   Deployment agent configuration (For agent instances).
Path : /Custom/config/atg/epub/DeploymentAgent.properties
File Content :
      deploymentEventListeners+=/com/test/service/listener/CustomDeploymentEventListener

4.   Deployment server configuration (For BCC instance).
Path : /Custom/config/atg/epub/DeploymentServer.properties
File Content :
       deploymentEventListeners+=/com/test/service/listener/CustomDeploymentEventListener

Monday, 13 October 2014

Discountable/Non -Discountable SKUs in ATG 10.2


Today I came to know the interested attribute (discountable) of SKU added in ATG 10.2. Oracle introduced this boolean attribute at SKU and Product level. The attribute value true means it is discountable. The false value means non-discountable. By default SKUs and Products are discountable.

Non-discountable items do act as qualifiers for the promotion but they will not receive the discount.

Example : There is an Order Level Promotion say Spend 100$ get 20% Off.

Case 1 : If Order contains only non-discountable SKUs. In this case customer won't get any discount.
Case 2 : If Order contain non-discountable SKUs worth 60$.And discountable SKUs worth 40$.Here customer will get only 8$ discount (20% off 40). Both (discountable and non discountable) SKUs will contribute the amount required to trigger the promotion.

Thursday, 2 October 2014

Indexing As Part of a Deployment

You can configure your environment so that when you run a deployment in Content Administration, indexing is automatically started after the deployment is finished. To make this automatic triggering occur, add the following three components and their configuration to the localconfig layer for your Content Administration server.

  1. /atg/commerce/endeca/index/CategoryToDimensionOutputConfig
      Specify the following property for this component.

      targetName=Production

     2.  /atg/commerce/search/ProductCatalogOutputConfig

      Specify the following property for this component.

      targetName=Production

   3.   /atg/search/SynchronizationInvoker

      Specify the following properties for this component.

      host=atg-production-server-host
      rmi=8860