Logger Mechanism in ATG

Types of log message:
  1. error
  2. warning
  3. info
  4. debug (Disabled)
  • atg.nucleus.GenericService is the ATG class which provides logging feature by default
  • Default error, warning and info is enabled
  • In Production, disable info and debug
  • Global.properties - used to set logging level at directory level or set of components 
  • ATG Developer can use(ATGLogColorizer.exe) tools to color log output   

Log files found in below location:
    /ATGDIR/home/logs
    /JBOSS/server/atg/logs

Endeca Utility - How to restore Endeca Dgraph?

An Endeca index can be recovered by reverting to a particular baseline/delta or partial update.  To do so, restart the MDEX Engine on the index files that were backed up after a particular baseline/delta and roll forward using any partial update files accrued since that baseline/delta.

To revert to a previously applied update:

1. Stop the MDEX Engine

2. Clean up the active dgraph_input directories

3. In the backup directory, locate the files from the last successful update.   This is the dgidx_output directory backup on the ITL server.

4. Copy the files into dgraph_input

5. If partial updates need to be applied, see instructions below on “Applying partial updates between last baseline/delta or snapshot and present”. Otherwise, restart the MDEX Engine.

Applying partial updates between last baseline/delta and present:

1. In the backup directory for partial update XML files (the cumulative_partials backup directory), locate the files representing the updates that occurred since the update you are reverting to. 

2. Copy all backed-up partial update XML configuration files from all partial updates that occurred since the update to which you want to revert into the dgraph_input/updates directory on the MDEX server.

3. Restart the MDEX Engine. Upon restarting, the Engine will load the current index and then apply all updates loaded into its updates directory.

ATG Shipping Groups, methods and calculators

Adding shipping information to shopping carts involves the following sub-processes:
1) Creating a list of shipping groups for potential use in the current order
2) Specifying the shipping groups to use with the current order
3) Selecting the shipping methods, such as Ground or Next Day, for the order’s shipping groups 


What is Shipping Group?
A ShippingGroup contains information on the shipping address and delivery method for a group of commerce items. 

By default, a new Order has one defaultShippingGroup. As items are added to the Order, these items automatically become part of the default ShippingGroup. Once a second ShippingGroup is added to theOrder, all the items in the Order are removed from the default ShippingGroup and must be explicitly added to one of two shipping groups. 
 
How to create new Shipping Groups?
You can create a list of shipping groups for potential use in an Order in one of two ways:
  • from information gathered from the user via forms

  • from information stored in the user’s profile
 Below two form handlers allow user to add new shipping groups  
  • /atg/commerce/order/purchase/CreateHardgoodShippingGroupFormHandler
  • /atg/commerce/order/purchase/CreateElectronicShippingGroupFormHandler
 Both extends PurchaseProcessFormHandler 

How to add Shipping Group to an Order?
Steps:
1) Create Shipping Group
2) Make any changes to the Shipping Group, such as setting the address
3) Add the Shipping Group to the Order


 Here is the code snippet:
// Get a reference to the OrderManager 
OrderManager orderManager = (OrderManager)   request.resolveName("/atg/commerce/order/OrderManager");  
// Create the ShippingGroup 
ShippingGroup shippingGroup shippingGroupManager.createShippingGroup(); 
// Add the ShippingGroup to the Order shippingGroup.addShippingGroupToOrder(pOrder, shippingGroup);

How to find available Shipping methods for a particular Shipping Group?
Use droplet  /atg/commerce/pricing/AvailableShippingMethods


How to initiate Shipping group from Profile?
Use droplet /atg/commerce/order/purchase/ShippingGroupDroplet
 
What is Shipping method? 
Each Shipping method is represented by ShippingCalculator component class.

Shipping methods examples are:
  • Ground
  • 2 day delivery
  • Overnight
  • Calculate Shipping price based on couriers web service
  • etc...
Different types of Shipping calculators are:
  • FixedPriceShippingCalculator - Flat rate for shipping
            Ex: Ground shipping is always $15
  • PriceRangeShippingCalculator - Define shipping price based price range
             Ex: $0 - $50  ($5)
                   $51 - $100  ($10)
                   $101 - $1000  (FREE)
  • WeightRangeShippingCalculator - Weight Property added at SKU level and price set based on weight
  • PropertyRangeShippingCalculator - Shipping price decided Based on SKU property
          Ex: Volume
    How to Filter Shipping methods?
    In few scenarios, All shipping methods should not be available. To limit shipping methods developer can sub-class Shipping calculator and override the getAvailableMethods().

    Ex: Courier shipping not allowed for PO boxes

    How to write custom shipping calculator?
    Here are the steps:
    1. Create a new custom calculator component 
    /com/commerce/shipping/FixedPriceServiceCaclulator.properties 
    $class=com.xxx.commerce.pricing.calculators.FixedPriceShippingCalculator
    # name of shipping method
    shippingMethod=DEMO
    # costs 
    amount=10.0

    2. Create a custom Java class and this should extends the shippingCalculatorImpl class
    ShippingCalculatorImpl class have two method for override.
    1.getAmount()  - calculate the shipping price

    2.getAvailableMethods()  - Used to restrict your custom shipping method

    public class FixedPriceShippingCalculator extends ShippingCalculatorImpl { 

    protected double getAmount(Order order, ShippingPriceInfo priceQuote, ShippingGroup shippingGroup, RepositoryItem pricingModel, Locale locale, RepositoryItem profile, Map extraParameters) throws PricingException { }

    public void getAvailableMethods(List pMethods, ShippingGroup pShippingGroup, RepositoryItem pPricingModel, Locale pLocale, RepositoryItem pProfile, Map pExtraParameters) throws PricingException {
    }
    }
    3. Add the shipping calculator to Shipping Engine
    /atg/commerce/pricing/ShippingPricingEngine.properties 
    preCalculators+=/com/commerce/shipping/FixedPriceServiceCaclulator

    How to Hide the list of applications on the login page? - Endeca Workbench

    By default, Workbench shows all available Endeca applications in a drop-down list on the login page. Business users can log in to any application that an administrator has added them to.

    In cases where you do not want Workbench users to see all available Workbench applications on the login page, you can hide the drop-down list of applications.

    To hide the drop-down list of applications on the login page:

    1) Stop the Endeca Tools Service

    2) Open the webstudio.properties file located in %ENDECA_TOOLS_CONF%\conf (on
    Windows) or $ENDECA_TOOLS_CONF\conf (on UNIX)

    3) Locate the com.endeca.webstudio.hide.login.application.dropdown property:

    # Hides the dropdown for selecting an application
    # on the default login page.
    com.endeca.webstudio.hide.login.application.dropdown=false


    4. Set the value of the property to true:com.endeca.webstudio.hide.login.application.dropdown=true

    5. Save and close the file

    6. Start the Endeca Tools Service

    Interaction between MDEX Engine and Workbench

    Endeca Workbench queries the MDEX Engine for information and publishes configuration to it.

    Experience Manager queries the MDEX Engine for record and dimension information that a content administrator can use to configure dynamic content.
    Examples:

    1. Specifying a navigation state as part of a location trigger
    2. Selecting records or a navigation state for content spotlighting
    3. Selecting records or dimension values for boost and bury
    Workbench publishes configuration to the MDEX Engine, including:
    1. Content item configuration from Experience Manager
    2. Content collections
    3. Thesaurus entries

    Inserting Servlets in the DAF Pipeline

    Inserting Servlets in the Pipeline
    All pipeline servlet classes directly or indirectly implement interface atg.servlet.pipeline.PipelineableServlet.

    The PipelineableServlet interface has two sub-interfaces that provide more flexibility for inserting new servlets into the pipeline:

    1. atg.servlet.pipeline.InsertableServlet
    2. atg.servlet.pipeline.DispatcherPipelineableServlet
    InsertableServlet
    The InsertableServlet interface lets a servlet insert itself into the pipeline when the service starts, without requiring changes to servlets already in the pipeline, through the insertAfterServlet property, which points back to the preceding servlet. The inserted servlet reads the preceding servlet’s nextServlet property and points to it as the next servlet to execute after itself.

    Here are the steps to add an InsertableServlet to the servlet pipeline:
    1) Write your servlet by extending atg.servlet.pipeline.InsertableServletImpl

    package com.foo.endeca.assembler;  
    import java.io.IOException;
    import javax.servlet.ServletException;
    import atg.core.util.StringUtils;
    import atg.eai.framework.toolkit.IdLookup;
    import atg.servlet.DynamoHttpServletRequest;
    import atg.servlet.DynamoHttpServletResponse;
    import atg.servlet.pipeline.InsertableServletImpl;     

    public class SearchkeywordRedirectPipeline extends InsertableServletImpl {
                   public void service(DynamoHttpServletRequest request, DynamoHttpServletResponse response) throws IOException, ServletException {
                 String searchTerm = null;
                searchTerm = request.getParameter("Ntt");
                //Business logic goes here
                logDebug("URL for searchTerm : " + searchTerm);
                passRequest(request, response);
           }
          
    2) Define the servlet as a globally scoped Nucleus component
          $class=com.foo.endeca.assembler.SearchkeywordRedirectPipeline
          $scope=global
          insertAfterServlet=/atg/dynamo/servlet/dafpipeline/CookieBufferServlet

    Set the insertAfterServlet property of your servlet to point to the path of the pipeline servlet you want your servlet to follow. For example, you can insert a servlet after CookieBufferServlet as follows:

    insertAfterServlet=/atg/dynamo/servlet/dafpipeline/CookieBufferServlet

    When the inserted servlet finishes processing, it calls the method passRequest() (defined in InsertableServletImpl), which automatically passes the request and response objects to the next servlet in the pipeline.

    Servlet Pipeline - All pipeline servlets in order of execution


    You can use the Dynamo Server Admin Component Browser to view request handling pipeline servlets and their sequence within the pipeline:

    Component path: /atg/dynamo/servlet/dafpipeline/DynamoHandler/


    /atg/dynamo/servlet/dafpipeline/DynamoHandler
    /atg/multisite/SiteContextPipelineServlet
    /atg/dynamo/servlet/dafpipeline/SecurityServlet
    /atg/dynamo/servlet/dafpipeline/TransactionServlet
    /atg/dynamo/servlet/dafpipeline/ThreadUserBinderServlet
    /atg/dynamo/servlet/dafpipeline/PathAuthenticationServlet
    /atg/dynamo/servlet/dafpipeline/URLArgumentServlet
    /atg/dynamo/servlet/dafpipeline/DynamoServlet
    /atg/dynamo/servlet/dafpipeline/ProfileRequestServlet
    /orion/locale/servlet/UpdateLocaleServlet
    /orion/location/servlet/UpdateLocationServlet
    /atg/dynamo/servlet/dafpipeline/ProfilePropertyServlet
    /atg/dynamo/servlet/dafpipeline/SessionEventTrigger
    /atg/dynamo/servlet/dafpipeline/SiteSessionEventTrigger
    /atg/search/servlet/pipeline/SearchClickThroughServlet
    /atg/dynamo/servlet/dafpipeline/PageViewServletTrigger
    /atg/dynamo/servlet/dafpipeline/SessionSaverServlet
    /atg/dynamo/servlet/dafpipeline/AccessControlServlet
    /atg/dynamo/servlet/dafpipeline/PromotionServlet     
    /atg/dynamo/servlet/dafpipeline/CommerceCommandServlet   
    /atg/dynamo/servlet/pagecompile/DAFDropletEventServlet
    /atg/dynamo/servlet/dafpipeline/MimeTyperServlet
    /atg/dynamo/servlet/dafpipeline/ExpiredPasswordServlet
    /atg/dynamo/servlet/dafpipeline/CookieBufferServlet
    /foo/endeca/assembler/SearchkeywordRedirectPipeline                     - New Servlet
    /atg/endeca/assembler/AssemblerPipelineServlet
    /atg/dynamo/servlet/dafpipeline/MimeTypeDispatcher
        dynamo-internal/html : /atg/dynamo/servlet/dafpipeline/FileFinderServlet
    /atg/dynamo/servlet/dafpipeline/TailPipelineServlet

    DAF : Request-Handling Pipeline Servlets

    You can use the Dynamo Server Admin Component Browser to view request handling pipeline servlets and their sequence within the pipeline:

    Component path: /atg/dynamo/servlet/dafpipeline/DynamoHandler/

    By default, PageFilter is mapped to handle JSP requests. When the application server invokes PageFilter, it checks the request and response for a reference to a Dynamo request and response pair. The pair does not exist, so PageFilter starts the DAF servlet pipeline by calling DynamoHandler, the first servlet in the pipeline.

    /WEB-INF/web.xml



    Servlet Pipeline(v11.1) - All pipeline servlets in order of execution.

               HTTP Request
                        |
                        |
                       V
    /atg/dynamo/servlet/dafpipeline/DynamoHandler
    /atg/multisite/SiteContextPipelineServlet
    /atg/dynamo/servlet/dafpipeline/SecurityServlet
    /atg/dynamo/servlet/dafpipeline/TransactionServlet
    /atg/dynamo/servlet/dafpipeline/ThreadUserBinderServlet
    /atg/dynamo/servlet/dafpipeline/PathAuthenticationServlet
    /atg/dynamo/servlet/dafpipeline/URLArgumentServlet
    /atg/dynamo/servlet/dafpipeline/DynamoServlet
    /atg/dynamo/servlet/dafpipeline/ProfileRequestServlet
    /orion/locale/servlet/UpdateLocaleServlet
    /orion/location/servlet/UpdateLocationServlet
    /atg/dynamo/servlet/dafpipeline/ProfilePropertyServlet
    /atg/dynamo/servlet/dafpipeline/SessionEventTrigger
    /atg/dynamo/servlet/dafpipeline/SiteSessionEventTrigger
    /atg/search/servlet/pipeline/SearchClickThroughServlet
    /atg/dynamo/servlet/dafpipeline/PageViewServletTrigger
    /atg/dynamo/servlet/dafpipeline/SessionSaverServlet
    /atg/dynamo/servlet/dafpipeline/AccessControlServlet
    /atg/dynamo/servlet/dafpipeline/PromotionServlet                       — CORE COMMERCE
    /atg/dynamo/servlet/dafpipeline/CommerceCommandServlet     — CORE COMMERCE
    /atg/dynamo/servlet/pagecompile/DAFDropletEventServlet
    /atg/dynamo/servlet/dafpipeline/MimeTyperServlet
    /atg/dynamo/servlet/dafpipeline/ExpiredPasswordServlet
    /atg/dynamo/servlet/dafpipeline/CookieBufferServlet
    /atg/endeca/assembler/AssemblerPipelineServlet
    /atg/dynamo/servlet/dafpipeline/MimeTypeDispatcher
        dynamo-internal/html : /atg/dynamo/servlet/dafpipeline/FileFinderServlet
    /atg/dynamo/servlet/dafpipeline/TailPipelineServlet

    How to load ATG component on Server startup?

    When you start up an application, Nucleus reads the configuration path. The out-of-the-box DAS module has (/DAS/config/config.jar/Nucleus.properties) Nucleus.properties component.

    Component path: /nucleus/
    $class=atg.nucleus.Nucleus
    # the default initially resolved service
    initialServiceName=/Initial

    The initialServiceName property instructs Nucleus to configure and start up its initial service using Initial.properties

    Component path: /nucleus/Initial
    Configuration: /nucleus/Initial/?propertyName=serviceConfiguration
    $class=atg.nucleus.InitialService
    initialServices=\
            atg/dynamo/service/PerformanceMonitor,\
    /atg/Initial,\
    VMSystem,\
    /atg/dynamo/StartServers,\
            /atg/dynamo/server/ServerMonitor


    In nucleus, to start any custom component at start up(when ATG server starts), Layer /nucleus/Initial.properties as below:

    initialServices+=\
                    /atg/search/CustomEndecaDimIdCacheService

    ATG - How to enable priceLists to store prices?

    Oracle Commerce users do not have a price list functionality available by default. By default prices are stored directly in the product catalog and OOTB configured using below component.

    Component Path: /atg/commerce/pricing/ItemPricingEngine
    Configuration:   /atg/commerce/pricing/ItemPricingEngine/?propertyName=serviceConfiguration

    preCalculators=\
            calculators/ItemListPriceCalculator,\
            calculators/ItemSalePriceCalculator,\
            calculators/ConfigurableItemPriceCalculator



    How to enable priceLists? 
    To add price list functionality, configure the ItemPricingEngine to use the appropriate precalculator. 
    Here is how you can override ItemPricingEngine component:
    Component Path: /atg/commerce/pricing/ItemPricingEngine

    preCalculators=\
        calculators/ItemPriceListCalculator,\
        calculators/ItemPriceListSaleCalculator,\
        calculators/ConfigurableItemPriceListCalculator,\
        calculators/ConfigurableItemPriceListSaleCalculator


    This means the prices are retrieved from the PriceLists repository 
    Price Lists created through BCC 
    Price can be defined at Product, SKU or Product/SKU pairing

    ATG User Profile Basics

    OOTB ATG Manages user profiles with a SQL repository
    SQL Repository Component : /atg/userprofiling/ProfileAdapterRepository
    Definition File: /atg/userprofiling/userProfile.xml
    Current user represented using Profile component (/atg/userprofiling/Profile) and exposes all the properties from the userProfile.xml

    There are two types of users:
    1) External Users

                Web Site registered users and are stored in ProfileAdapterRepository
    2) Internal Users

            Company users who need access to BCC, CSC etc.. and are stored in InternalProfileRepository

    Profile Repository definition file layering: (/atg/userprofiling/ProfileAdapterRepository/?propertyName=definitionFiles)

    /DPS/config/profile.jar/atg/userprofiling/userProfile.xml
    /DSS/config/config.jar/atg/userprofiling/userProfile.xml
    /DCS/config/config.jar/atg/userprofiling/userProfile.xml
    /APPLICATION_NAME/config/config.jar/atg/userprofiling/userProfile.xml

    ProfileFormHanlder:
    Component path: /atg/userprofiling/ProfileFormHandler/
    This component helps to create, update, login, logout, change password etc…

    Various methods available are:
    • handleCreate()
    • handleUpdate()
    • handleCancel()
    • handleDelete()
    • handleLogin()
    • handleLogout()
    • handleChangePassword()
    How to create a new user?
    Here is a code snippet:

     
     

    How to check if user is logged in or Anonymous?
    Using /atg/userprofiling/Profile.transient property. It returns false, if the Profile is saved. Otherwise true will be returned.

     

    ATG Shopping Cart Basics

    User can use Product Page or Cart page to perform below actions:
    1. Add Item(s) to the cart
    2. Remove Item from the cart
    3. Change quantity of item(s)
    4. Delete item(s) from the cart
    How to add item(s) to the cart?
    • OOTB ATG provides request scope CartModifierFormHandler component with pre-build methods for add, update, delete etc..
    • Component path : /atg/commerce/order/purchase/CartModifierFormHandler


    What happens when user adds item(s) to the cart?
    • When SKUs are added to the order, they become CommerceItem objects
    • CommerceItem Object represent each line item in the order
    • Order may contain many commerce items object
    How to check the order object and commerce Items?
    •    ShoppingCart is session scoped component  (/atg/commerce/ShoppingCart)
    •    ShoppingCart uses OrderHolder Class to hold multiple orders
    •    At any given point only one Order will be active
    •    ShoppingCart holds current, saved and last orders
    •    Current Order object can be accessed by using either ShoppingCart.current or CartModifierFormHandler.order

    ATG Component layering and how it works?

    The config files (.properties) are layered in ATG. If the same .property files is present in modules which are dependent, then it will merge the property values.

    Scenario #1:
    Module A has X.properties with values name and age and depends on Module B which has X.properties with age and address.


    When Module A component is involved it takes the values of age (overridden in A) and name from X.properties of A and address from X.properties of B.

    Scenario #2:
    Multi value property
    #1    X.properties in the config of component contains

                  vehicles=car, bike
            X.properties in the localconfig contains
                  vehicles=bus
    Then when this is used in the jsp then only bus is selected.

    #2 To add all items, then, we need to use the below notation in the overridden file:
                   vehicles+=bus

    #3 If we need car and bus and bike to be removed then, we need to use the below notation in the overridden file:

                  vehicles+=bus
                  vehicles-=bike

    ATG Order Reprice and How it works?

    When Order reprice is typically called?
    The Order is typically repriced after the following actions: 
    • Item is added to the cart 
    • Item is removed from the cart 
    • Quantity is changed on items in the cart 
    • User specifies a shipping address or shipping method and pushes "Checkout" button
    How to do repricing on Order?
    Use /atg/commerce/order/purchase/RepriceOrderDroplet to invoke repricing on order:



    How it works behind the scenes?
    Each time the code reprices the order, the ATG Promotions associated with the user's Profile are considered.
    • Fetch all of the Promotions/Discounts that the user is eligible for:
      • (Global + Individual Promotions) minus Promotions they don't qualify for
    • Calculate the price of each individual item on the order
      • Apply Item Level Discounts
    • Calculate the order total price(discounted item prices + shipping price)
      • Apply Order Level discounts
    • Calculate the shipping price
      • Apply Shipping Discounts
    • Generate a total price
    Few scenarios when Order reprice is not working:
    If you don't see your order getting repriced as you expected (the discount isn't being related), these are some things to check on:
    • Was the repricing code called yet?
    • Was the Promotion successfully added to the Profile?
    • Was the Promotion represented correctly in the repository?  
     

    ATG - Promotions 101

    What is Promotion?
    A Promotion is an item created in the BCC that contains information about a possible discount that some (or all) users on your site may be able to get. Promotions specify a discount amount, and a conditional rule.

    There are two types of Promotions:
     1) Global 

    • Automatically granted to all users
    •  If order qualifies, discount is given
     2) Individual 
    • Not automatically granted to all users
    • Something (typically a Scenario) has to grant the Promotion to the user before they can get the discount
    What happens at User "Profile" component level?
    • When a user comes to your site, ATG will create a "Profile" component for this user. 
    • This ATG Profile component sticks around for the entire user session. It goes away when the user terminates their session. 
    • This Profile contains a property called "activePromotions" – this is a list of 0 or more Promotions that this user has been given. 
    • Each time your order is repriced, the code looks in Profile.activePromotions plus all Global Promotions to see which promotions the user is eligible for and reprices the order accordingly.

     How a user gets promotion(s)?
    •  If you create a Global Promotion, all users will automatically be given the Promotion (remember: they may not qualify – but it is always in their list of "possible promotions")
    •  If you create an Individual Promotion, the associated Promotion must first be "given" to the user. If the Individual Promotion is not in the Profile.activePromotions property, the user will not get the discount even if they qualify.
    • If a Scenario adds a Promotion to the user's Profile.activePromotions property, but the user doesn't actually qualify for it, a discount will not be given when the order is repriced
    There are a number of ways Individual Promotions can be granted to the user. 
    Commonly used one's are:
    1. Scenarios   -  Create a Scenario such as: If order.total is >= 50$, give user promotion: 10Off50, or if user logs in, and Profile.age > 62 and today is Wednesday, then give user a 20SeniorWednesday promotion 
    2. Coupons - User enters a coupon code associated with Promotion 10Off50. The Promotion is added to Profile.activePromotions

    ATG Repository queries using dyn/admin

    Product Catalog
    Component: /atg/commerce/catalog/ProductCatalog/
     

    Profile Adapter Repository
    Component: /atg/userprofiling/ProfileAdapterRepository/
     


    Order Repository
    Component:  /atg/commerce/order/OrderRepository/
     


    ATG Component scope

    Component Scope:
    1) global
    2) session
    3) request

    global can access only global
    session can access session and global
    request can access request, session and global

    Global:

    $scope=global
    - Default scope 
    - Its instance is shared by users across all the sessions that exist for the application (Not similar to application scope of J2EE as global scope components are accessible across application but across ATG server instances)
    - Any user which accesses the application can change the values of a global scoped component

    Session:
    $scope=session
    - A separate instance is provided for each session or user
    - Session by default valid for 30 mins


    How to track and manage user sessions?
    Use component:  /atg/dynamo/servlet/sessiontracking


     

    Ex: OOTB Session based component /atg/userprofiling/Profile

    Request:

    $scope=request
     - Each request gets own copy of component
    - A new instance will be generated for the component
    - Formhandler is always request scoped