Friday, October 3, 2014

ATG integration with Weblogic publishing ear in admin console

The first step is to build ear using ant build xml file. The ear file contains many project which will be bundled under single ear to deploy on weblogic server. To deploy on weblogic the following steps should be followed:

1) Create DB connection setup in weblogic admin console for PROD_CATA, PROD_CATB & PROD_CORE
2) Create App server
3) Attach DB targets for the app server where ear has to be deployed
4) Deploy the ear in admin console
5) start server

Many app server can be created and multiple ear can be deployed on each server on different ports like publishing server, production server & POC server etc...

ATG ACC setup for updating catalog

Build BCC ear using ant build xml file. The ear file should be deployed on publishing server in admin console for BCC setup.

ACC can be used on production schema for development purpose.
To open GUI, invoke "startACC.bat" from c:\ATG\ATG11.0\home\bin

Enter credential admin/admin and connect to production server.
It has various option for updating/creating new data for catalog Management, category hierarchy, product/sku creation/update, Targeters, Scenarios, content etc...
New repository can also be added to update via ACC by updating file: atg/registry/ContentRepositories

ACC can be used even for pipeline design, browsing all jsp under war deployed on app servers.
Mostly used to update category hierarchy, data population for item descriptors defined either in customCatalog.xml or any repository xml file.


ATG Inventory Manager basics

InventoryManager Implementations
Oracle ATG Web Commerce includes the following implementations of the InventoryManager out of the box.

  1.     AbstractInventoryManagerImpl
  2.     NoInventoryManager
  3.     RepositoryInventoryManager
  4.     CachingInventoryManager
  5.     LocalizingInventoryManager
  6.     RepositoryInventoryManager

RepositoryInventoryManager
 This is a repository based implementation of InventoryManager. It implements all the methods defined by the InventoryManager API. It is a thin wrapper around a repository that contains the inventory information. This allows a maximum amount of flexibility for potential third party integrators. Integrators can simply implement a repository containing the required properties for cooperation with the RepositoryInventoryManager. The Repository InventoryManager can then be configured to extract inventory manager information from the third party repository.

This class also is a message source. It can send UpdateInventory messages if there is new inventory available for a previously unavailable item.

StoreInventoryManager
This class is an extension of the RepositoryInventoryManager. It will be responsible for writing to the inventory repository. This should only happen from the fulfillment server.

Caching the Inventory
      By default, caching is turned off for the inventory repository. This is to insure that inventory data is always up to date across server instances. The CachingInventoryManager is provided as an effective inventory caching mechanism for displaying inventory information.
      
      The CachingInventoryManager can be used to display information to customers as they browse the product catalog because, in most situations, inventory information displayed to customers during catalog browsing does not need to be updated in real time. Displaying inventory information using the CachingInventoryManager improves the performance of the site.
      
      The CachingInventoryManager should not be used when real time inventory data is needed. Real time inventory information is usually needed during the purchase process and fulfillment process. In those cases, the (uncached) InventoryManager should be used during these processes. For more information on the CachingInventoryManager, see the InventoryManager Implementations section.
      
      The InventoryDroplet provides cached data to the user when appropriate and accesses real time inventory data from the repository when appropriate. The useCache property allows you to indicate when to use cached inventory data:
      
          If the useCache property is set to false, the inventory data in the repository is provided.
      
          If the useCache property is set to true, the cached data is provided.
      
The GSA can provide more complex types of caching. If appropriate, you can configure two instances of the InventoryRepository GSA, one with no caching and one with distributed caching (set cache-mode=distributed). You can configure one instance of the RepositoryInventoryManager to use the uncached GSA, and another instance of the RepositoryInventoryManager to use the cached GSA. For more information on distributed caching, see the SQL Repository Caching chapter in the ATG Repository Guide.


ATG Commerce Schema

The ATG Commerce database schema includes the following types of tables:
  1.     Product Catalog Tables
  2.     Commerce Users Tables
  3.     Claimable Tables
  4.     Shopping Cart Events Table
  5.     Inventory Tables
  6.     Order Tables
  7.     Promotion Tables
  8.     User Promotion Tables
  9.     Gift List Tables
  10.     Price List Tables
  11.     Custom Catalog Tables
  12.     Abandoned Order Services Tables
  13.     Order Markers Table


    Product Catalog Tables:  ATG Commerce uses the following tables to store product catalog information:
  1.         dcs_folder
  2.         dcs_media
  3.         dcs_media_ext
  4.         dcs_media_bin
  5.         dcs_media_txt
  6.         dcs_category
  7.         dcs_product
  8.         dcs_product_acl
  9.         dcs_sku
  10.         dcs_cat_groups
  11.         dcs_cat_chldprd
  12.         dcs_cat_chldcat
  13.         dcs_cat_ancestors
  14.         dcs_cat_rltdcat
  15.         dcs_cat_keywrds
  16.         dcs_cat_media
  17.         dcs_cat_aux_media
  18.         dcs_prd_keywrds
  19.         dcs_prd_media
  20.         dcs_prd_aux_media
  21.         dcs_prd_chldsku
  22.         dcs_prd_skuattr
  23.         dcs_prd_groups
  24.         dcs_prd_rltdprd
  25.         dcs_prd_ancestors
  26.         dcs_sku_attr
  27.         dcs_sku_link
  28.         dcs_sku_bndllnk
  29.         dcs_sku_media
  30.         dcs_sku_aux_media
  31.         dcs_sku_replace
  32.         dcs_sku_conf
  33.         dcs_config_prop
  34.         dcs_conf_options
  35.         dcs_config_opt
  36.      dcs_foreign_cat


Commerce Users Tables:  ATG Commerce uses the following tables to store information about commerce users:
  1.     dps_credit_card
  2.     dcs_user
  3.     dps_usr_creditcard


Claimable Tables:  ATG Commerce uses the following table to store claimable information:
  1.     dcspp_claimable
  2.     dcspp_giftcert
  3.     dcs_storecred_clm
  4.     dcspp_coupon


Shopping Cart Events Table:   ATG Commerce uses the following table to store information about shopping cart events:

  1. dcs_cart_event
Inventory Tables:  ATG Commerce uses the following tables to store inventory information:

  1. dcs_inventory

Order Tables:   ATG Commerce uses the following tables to store order information:

  1.     dcspp_order
  2.     dcspp_ship_group
  3.     dcspp_pay_group
  4.     dcspp_item
  5.     dcspp_relationship
  6.     dcspp_rel_orders
  7.     dcspp_order_inst
  8.     dcspp_order_sg
  9.     dcspp_order_pg
  10.     dcspp_order_item
  11.     dcspp_order_rel
  12.     dbcpp_sched_order
  13.     dcspp_ship_inst
  14.     dcspp_hrd_ship_grp
  15.     dcspp_ele_ship_grp
  16.     dcspp_ship_addr
  17.     dcspp_hand_inst
  18.     dcspp_gift_inst
  19.     dcspp_sg_hand_inst
  20.     dcspp_pay_inst
  21.     dcspp_config_item
  22.     dcspp_subsku_item
  23.     dcspp_item_ci
  24.     dcspp_gift_cert
  25.     dcspp_store_cred
  26.     dcspp_credit_card
  27.     dcspp_bill_addr
  28.     dcspp_pay_status
  29.     dcspp_cc_status
  30.     dcspp_gc_status
  31.     dcspp_auth_status
  32.     dcspp_debit_status
  33.     dcspp_cred_status
  34.     dcspp_shipitem_rel
  35.     dcspp_rel_range
  36.     dcspp_det_range
  37.     dcspp_payitem_rel
  38.     dcspp_payship_rel
  39.     dcspp_payorder_rel
  40.     dcspp_amount_info
  41.     dcspp_order_price
  42.     dcspp_item_price
  43.     dcspp_tax_price
  44.     dcspp_ship_price
  45.     dcspp_amtinfo_adj
  46.     dcspp_price_adjust
  47.     dcspp_itmprice_det
  48.     dcspp_det_price
  49.     dcs_submt_ord_evt
  50.     dcs_ord_merge_evt
  51.     dcspp_order_adj
  52.     dcspp_manual_adj


Promotion Tables:  ATG Commerce uses the following tables to store information about promotions:

  1.     dcs_promotion
  2.     dcs_promo_media
  3.     dcs_discount_promo
  4.     dcs_promo_upsell
  5.     dcs_upsell_action
  6.     dcs_close_qualif
  7.     dcs_prm_cls_qlf
  8.     dcs_upsell_prods
  9.     dcs_prom_used_evt
  10.     dcs_promo_rvkd
  11.     dcs_promo_grntd


User Promotion Tables:  ATG Commerce uses the following tables to store information about user promotions:

  1.     dcs_usr_promostat
  2.     dcs_usr_actvpromo
  3.     dcs_usr_usedpromo


Gift List Tables:  ATG Commerce uses the following tables to store information about gift lists and wish lists:

  1.     dcs_giftlist
  2.     dcs_giftinst
  3.     dcs_giftitem
  4.     dcs_giftlist_item
  5.     dcs_user_wishlist
  6.     dcs_user_giftlist
  7.     dcs_user_otherlist


Price List Tables:  The following database tables store information related to price lists.

  1.     dcs_price_list
  2.     dcs_complex_price
  3.     dcs_price
  4.     dcs_price_levels
  5.     dcs_price_level
  6.     dcs_gen_fol_pl
  7.     dcs_child_fol_pl
  8.     dcs_plfol_chld


Custom Catalog Tables:  The following database tables store information related to the custom catalogs.

  1.     dcs_catalog
  2.     dcs_root_cats
  3.     dcs_allroot_cats
  4.     dcs_root_subcats
  5.     dcs_sub_catalogs
  6.     dcs_category_info
  7.     dcs_product_info
  8.     dcs_sku_info
  9.     dcs_cat_subcats
  10.     dcs_cat_subroots
  11.     dcs_cat_catinfo
  12.     dcs_catinfo_anc
  13.     dcs_prd_prdinfo
  14.     dcs_prdinfo_rdprd
  15.     dcs_prdinfo_anc
  16.     dcs_sku_skuinfo
  17.     dcs_skuinfo_rplc
  18.     dcs_gen_fol_cat
  19.     dcs_child_fol_cat
  20.     dcs_catfol_chld
  21.     dcs_dir_anc_ctlgs
  22.     dcs_ind_anc_ctlgs
  23.     dcs_ctlg_anc_cats
  24.     dcs_cat_prnt_ctlg
  25.     dcs_cat_anc_cats
  26.     dcs_prd_prnt_cats
  27.     dcs_prd_anc_cats
  28.     dcs_cat_catalogs
  29.     dcs_prd_catalogs
  30.     dcs_sku_catalogs
  31.     dcs_user_catalog


Abandoned Order Services Tables:  ATG Commerce uses the following tables to store information about users’ abandoned orders:

  1.     dcspp_ord_abandon
  2.     dcs_user_abandoned
  3.     drpt_conv_order
  4.     drpt_session_ord


Order Markers Table:  The following section describes the table used to hold order marker information.
  1. dcs_order_marker

ATG Commerce with Custom Catalogs

Custom Catalogs allow you to set up your product catalog so different customers see different information about the products they view, or different products altogether.

ATG Commerce run in two separate modes:

development mode: Uses derived properties so that you can preview a product catalog on a web site while you’re making changes without having to run the batch service (CatalogMaintenanceService). Development mode makes the updates incrementally so you can preview your changes throughout the development process.
Development mode overrides the definitions of certain properties in the catalog repository that are normally computed by the batch service, and these properties are derived on-the-fly. Development mode is more resource intensive than production mode because these properties have to be computed at the time they are referenced, rather than being pre-computed by the batch service.

The development mode allows you to preview the custom catalogs as you edit them.

production mode: Uses computed properties. This mode uses the properties pre-computed by the batch service, so performance is upgraded over development mode because time is no longer spent deriving the property values.

The production mode is the most efficient mode to run in when you won’t need to preview changes to the custom catalog.

ATG Catalog Maintenance System (CMS)

ATG catalogs use several batch and dynamic services to perform catalog updates and to verify catalog relationships. These services are collectively referred to as the Catalog Maintenance System (CMS). The CMS updates property values that enable navigation and hierarchical search. It also verifies the relationships of catalog repository items and properties.

Batch Services
There are four services that facilitate the updating of the catalog in batch mode. All batch services can be run on demand or in scheduled mode. They are:

  1. AncestorGeneratorService
  2. CatalogVerificationService
  3. CatalogUpdateService
  4. CatalogMaintenanceService


Dynamic Services
Dynamic Services consists of components that enable the catalog properties to be dynamically updated as the catalog structure is modified by an ACC user, BCC user, or a program using the Repository API.

  1. CatalogChangesListener
  2. CatalogCompletionService
  3. StandardCatalogCompletionService

ATG Pipeline Manager

The Pipeline Manager controls a series of processors, which make up a processor chain. Each processor in the processor chain is a component that performs a specific function and returns a status code. The status code can determine which processor to execute next.

The PipelineManager Nucleus component for ATG Commerce is located at /atg/commerce/PipelineManager. In ATG Consumer Commerce, the related XML configuration file is defined in <ATG9dir>/B2CCommerce/config/atg/commerce/commercepipeline.xml.

The following pipeline chains are defined in commercepipeline.xml.
  1. updateOrder Pipeline Chain: Saves the order supplied to it.
  2. loadOrder Pipeline Chain: Loads the order from the repository whose ID is supplied as a parameter.
  3. refreshOrder Pipeline Chain: Reloads an order after an error and causes the unloaded portion of an Order to be loaded when accessed.
  4. processOrder Pipeline Chain: Submits the given order for checkout.
  5. validateForCheckout Pipeline Chain: Verifies that the order is ready for checkout.
  6. validatePostApproval Pipeline Chain: Revalidates an order after approval.
  7. validatePaymentGroupsPostApproval Pipeline Chain: Validates each payment group in an order after the order has been approved.
  8. validateNoApproval Pipeline Chain: Validates an order that does not require approval.
  9. recalcPaymentGroupAmounts Pipeline Chain: Regenerates the amount that must be assigned to each PaymentGroup in the order.
  10. repriceOrder Pipeline Chain: Prices the order
  11. moveToConfirmation Pipeline Chain: Prices the order and validates it.
  12. moveToPurchaseInfo Pipeline Chain: Validates the order.
  13. validateShippingInfo Pipeline Chain: Validates the shipping groups in the order.
  14. sendScenarioEvent Pipeline Chain: Sends a message to the Dynamo Message System
/atg/commerce/invoice/pipeline/InvoicePipelineManager
/atg/commerce/payment/PaymentPipelineManager
/atg/commerce/PipelineManager


/atg/commerce/PipelineManager/

$class=atg.commerce.pipeline.CommercePipelineManager

# The location of the XML configuration file in the classpath.
# Default: /atg/commerce/CommercePipeline.xml
definitionFile=/atg/commerce/commercepipeline.xml


# The transaction manager that the PipelineManager will use to coordinate its
# transactions.
transactionManager=/atg/dynamo/transaction/TransactionManager

Steps to create pipeline:
1) update commercepipeline.xml
<pipelinechain name="moveToConfirmation" transaction="TX_REQUIRED" headlink="executeMyCustomChain" xml-combine="append">
      <pipelinelink name="executeMyCustomChain2" transaction="TX_MANDATORY">
         <processor jndi="/atg/commerce/order/processor/ExecuteValidateForCheckoutChain"/>
        <transition returnvalue="1" link="executeMyCustomChain3"/>
      </pipelinelink>
       <pipelinelink name="executeMyCustomChain3" transaction="TX_MANDATORY">
               <processor jndi="/com/test/processor/ProcessMyPipeline"/>
       </pipelinelink>     
       </pipelinechain>
2) CustomPipeline.properties
pipelineManager=/atg/commerce/PipelineManager
moveToConfirmationPipelineProcess=moveToConfirmation 
3) public class CustomPipelineFormHandler extends PaymentGroupFormHandler {
........................
public void runProcessMoveToConfirmation(DynamoHttpServletRequest pRequest,
            DynamoHttpServletResponse pResponse) {
            ............
PipelineResult result =  runProcess(moveToConfirmationPipelineProcess(), ....);
            processPipelineErrors(result);


Adding a Commerce Processor Using XML Combination

There are two ways to extend a pipeline defined for a PipelineManager. One is to copy the entire XML file into your CONFIG layer and make the necessary changes. The other way is to use XML combination. Using XML combination is the preferred approach. The example below demonstrates of how to use XML combination to modify a pipeline chain.

The XML below is a section of the processOrder pipeline chain as it appears out of the box.

<pipelinechain name="processOrder" transaction="TX_REQUIRED"
           headlink="executeValidateForCheckoutChain">
  <pipelinelink name="executeValidateForCheckoutChain" transaction="TX_MANDATORY">
     <processor
            jndi="/atg/commerce/order/processor/ExecuteValidateForCheckoutChain"/>
     <transition returnvalue="1" link="checkForExpiredPromotions"/>
  </pipelinelink>
  <pipelinelink name="checkForExpiredPromotions" transaction="TX_MANDATORY">
     <processor jndi="/atg/commerce/order/processor/CheckForExpiredPromotions"/>
     <transition returnvalue="1" link="removeEmptyShippingGroups"/>
</pipelinelink>

The following example demonstrates how to add a new processor called purgeExcessOrderData between the executeValidateForCheckoutChain and checkForExpiredPromotions processors in the processOrder pipeline chain. The following XML code should be added to your config layer.

The important sections of this code are the additions of the xml-combine attributes in the pipelinechain and pipelinelink tags. The pipelinechain tag indicates what is being appended to its contents. The pipelinelink tag for executeValidateForCheckoutChain indicates what is replacing its contents.

<pipelinemanager>
 <pipelinechain name="processOrder" transaction="TX_REQUIRED"
            headlink="executeValidateForCheckoutChain" xml-combine="append">
   <pipelinelink name="executeValidateForCheckoutChain" transaction="TX_MANDATORY"
         xml-combine="replace">
     <processor
           jndi="/atg/commerce/order/processor/ExecuteValidateForCheckoutChain"/>
     <transition returnvalue="1" link="purgeExcessOrderData"/>
   </pipelinelink>
   <pipelinelink name="purgeExcessOrderData" transaction="TX_MANDATORY">
     <processor jndi="/atg/commerce/order/processor/PurgeExcessOrderData"/>
     <transition returnvalue="1" link="checkForExpiredPromotions"/>
   </pipelinelink>
 </pipelinechain>
</pipelinemanager>

The purgeExcessOrderData processor’s transition is what the executeValidateForCheckoutChain's transition is in the base file within the commerce platform.


Managing cart with cookies

Cookies play very important role in e-commerce application. Here I am talking about managing cart with cookies. Its very interesting and need to understand better its limitation and challegnes.

I feel that cookie can be used for sharing cart as well managing cart in multiple JVMs.
If DB is same for the application then its easy to offer cart by loading order from DB. The challenge start if DB is not shared and multiple application wanted to share cart during checkout flow.

First we need to create cookie with all required attributes like: sku_id, product_id, promo_id, catalog_id etc... After all values are set, need to encrypt the data, set expiry time before adding to browser cookie.

This cookie can be read in application to load commerce item. It can be used load order, merge order with existing order and even persist order to DB by decrypting the cookie data.

We have to make sure cookies are secure.

Device detection principles

The device detection logic play very important role where we have to offer omni channel experience across multiple devices. The easiest and quicket way is to check user agent. We can also use regular expression to detect device from user agent. But it becomes more error prune where many devices keep coming every day and we need to support compatible services to all devices.

There is also a way to to store these agent info in DB. Persisting DB make sure we have detected many devices correctly for offering better user experience. In case we don't find any entry in DB that must be new device, can do a write operation to include this agent as well. Persisted user agent can be loaded and use regular expression for better matching agent to offer most suitable user experience.

ATG adding item to cart purchange process fundamentals

The CartModifierFormHandler is used to add items to and remove items from an Order, modify the quantity of items in the Order, and prepare the Order for the checkout process.

CartModifierFormHandler is an instance of class atg.commerce.order.purchase.CartModifierFormHandler; it is located in Nucleus at /atg/commerce/order/purchase/CartModifierFormHandler. Many of the methods (described below) in CartModifierFormHandler call OrderManager.updateOrder() to save the Order in its present state to the Order Repository. For information on OrderManager.updateOrder() and the updateOrder pipeline that it executes, see the Updating an Order with the OrderManager subsection of Saving Orders in this chapter.

The following sections describes the important methods in CartModifierFormHandler. As can be seen from the method descriptions that follow, the handleAddXXX and handleRemoveXXX methods of CartModifierFormHandler automatically reprice the Order whenever the user makes changes to it.

However, you should note that users can also make changes to their orders through other purchase process form handlers that do not reprice orders, such as the form handlers that create and manage shipping groups. In these situations, where the user can change the current Order in ways that affect its price, and where the form handler used to process those changes does not reprice the Order, you should use the RepriceOrderDroplet servlet bean to reprice the Order before displaying its price to the user.

When a customer adds an item to their shopping cart using CartModifierFormHandler, the submit button on the form submits to the handleAddItemToOrder method. Before any computation is done, the handleAddItemToOrder method invokes the preAddItemToOrder method. Additionally, after all computation is complete but before returning any information, the handleAddItemToOrder method invokes the postAddItemToOrder method.

CartModifierFormHandler.java
handleAddItemToOrder has following steps:
Create Order:
Order order = getOrder();

preAddItemToOrder - do validation for sku as active, check inventory etc...
addItemToOrder
postAddItemToOrder
updateOrder


RepeatingRequestMonitor rMonitor = getRepeatingRequestMonitor();
        String cartHandler = "CartModFormHandler.addItemOrder";
        if ((rMonitor == null) || (rMonitor .isUniqueRequestEntry(myHandleMethod))) {
            Transaction sTransaction = null;
            try {
                sTransaction = ensureTransaction();
                Order order = getOrder();
                synchronized (order) {                   
                    preAddItemToOrder(pRequest, pResponse);
                    addItemToOrder(pRequest, pResponse);
                    postAddItemToOrder(pRequest, pResponse);
                    updateOrder(order, "Error", pRequest, pResponse);
                }
                return checkFormRedirect(getAddItemToOrderSuccessURL(),
                        getAddItemToOrderErrorURL(), pRequest, pResponse);
            }

     finally {
                if (tr != null){
                    commitTransaction(tr);
                }
                if (rMonitor != null) {
                    rMonitor .removeRequestEntry(cartHandler);
                }

PurchaseProcessHelper role in purchase process

PurchaseProcessHelper contains the common functionality required by the purchase process form handlers as well as commerce web services.

getPurchaseProcessHelper().adjustItemRelationshipsForQuantityChange(order,item,quantity)
getPurchaseProcessHelper().deleteItems();
getPurchaseProcessHelper().addItemsToOrder();
getPurchaseProcessHelper().getFirstShippingGroup();
getPurchaseProcessHelper().createOrder();
getPurchaseProcessHelper().runProcessAddItemToOrder()

CartModifierFormHandler uses PurchaseProcessHelper to interact with pipeline processors and CommerceItemManager while adding/editing the cart.

 addItemToOrder() method retrieves the list of items to add by calling CartModifierFormHandler.getItems(), and calls CartModifierFormHandler.getCatalogKey() to determine which catalog to use. Then, for each item to add to the Order, the method uses the PurchaseProcessHelper class to do the following:

Creates a CommerceItem using the commerceItemType, catalogRefId, productId and quantity found in the current array element from getItems(). Adds the created CommerceItem to the order. Copies custom values from the current item’s value Dictionary to the new CommerceItem. Calls the PurchaseProcessHelper.getShippingGroupForItem() method to get a shipping group of the appropriate type. The type can be determined in one of three ways.

  1. Passed in to PurchaseProcessHelper from the CartModifierFormHandler.getItems()[ ].shippingGroupType. The passed-in type is used along with the item’s gift information (if any) to determine the correct shipping group to which the item should be added.       
  2.  Use the first shipping group of the passed-in type (if that information is available) or the first shipping group on the order, regardless of the item type. If this is the desired behavior (perhaps you only sell goods with one shipping group type, and the default is always the correct type), set the addItemToDefaultShippingGroup property of the /atg/commerce/order/purchase/PurchaseProcessHelper component to true. This property is set to true by default.
  3.         PurchaseProcessHelper can determine the correct group from the item type (based on the SKU’s fulfiller property value) and gift information. To use this behavior, set the addItemToDefaultShippingGroup property of the /atg/commerce/order/purchase/PurchaseProcessHelper component to false.


 Calls PurchaseProcessHelper.addItemToShippingGroup(), which calls CommerceItemManager.addItemQuantityToShippingGroup() which in turn takes the given quantity of the CommerceItem and the given ShippingGroup and creates a ShippingGroupCommerceItemRelationship of type SHIPPINGQUANTITY.

For information on the SHIPPINGQUANTITY type of ShippingGroupCommerceItemRelationship, see Relationship Types in the Using Relationship Objects section of the Working With Purchase Process Objects chapter.

Calls createConfigurableSubitems(), which is an empty method that can be overridden as needed by sites that use configurable commerce items.

Calls processGiftAddition(), which checks if the item that was added to the order is a gift (that is, the item’s input giftlistId or giftlistItemId property is non-null). If the item is a gift, processGiftAddition() calls GiftListManager.addGiftToOrder() to perform additional gift list processing.

After the above steps have been taken for all the new items, addItemToOrder() calls runProcessRepriceOrder(), which reprices the Order by executing the pipeline set in CartModifierFormHandler.repriceOrderChainId. Then, for each new item addItemToOrder() calls runProcessAddItemToOrder(), which executes the pipeline set in CartModifierFormHandler.addItemToOrderChainId. Finally, the method fires a scenario event of type ItemAddedToOrder for each new item.





ShoppingCart steps how to create and manage it

ShoppingCart component stores a user’s current and saved shopping carts. You can use the ShoppingCart component’s properties and handle methods to create a new shopping cart or retrieve one of the user’s saved shopping carts and make it the user’s current shopping cart. Shopping cart is an Order in an INCOMPLETE state. The shopping cart stores the information about the items a given customer wants to order and their associated quantities and prices. In addition, it stores the shipping and payment information for the order.

ShoppingCart Component
The ShoppingCart component is responsible for storing and managing a customer’s shopping carts. It maintains the customer’s current shopping cart that is used during the purchase process, and it stores any other shopping carts that have been persisted by that customer. These shopping carts are represented as atg.commerce.order.Order objects in the Oracle ATG Web Commerce object model, and represented as order items in the Order Repository.

By default, the /atg/commerce/ShoppingCart component is a session-scoped instance of atg.commerce.order.OrderHolder.

 Managing Shopping Carts
    Creating and Retrieving Shopping Carts
    Adding Items to Shopping Carts
    Adding Shipping Information to Shopping Carts
    Adding Payment Information to Shopping Carts
    Repricing Shopping Carts
    Saving Shopping Carts

ShoppingCart.savedEmpty property is checked to determine whether the current user has any saved shopping carts. If the user doesn’t have any saved shopping carts, the user can be given the option to create one. If the user has saved shopping carts, the user can be given the option to select one of the saved shopping carts.

OrderLookup servlet bean used to retrieve a user’s incomplete orders (that is, shopping carts). OrderLookup enables to retrieve a single order, all orders assigned to a particular cost center , all orders placed by a particular user, or all orders placed by a particular user that are in specific state, such as INCOMPLETE. Once the desired shopping cart is moved to ShoppingCart.current, you can use a ForEach servlet bean to iterate over the commerce items in the cart and display them.

When the user clicks the Add To Cart submit button, the form is processed, the properties of CartModifierFormHandler are set, and the handleAddItemToOrder method of CartModifierFormHandler is invoked. The handleAddItemToOrder method adds the quantity (specified in CartModifierFormHandler.quantity) of the selected SKU (specified in CartModifierFormHandler.catalogRefIds and identified by repository ID) to the current Order and then re-prices the Order.

Adding Multiple Items at Once

You can create pages that allow users to add multiple items to the current shopping cart in a single form submission. The items can refer to different products, different SKUs, and have different quantities. The CartModifierFormHandler contains an items property that allows you to set per-item property values.

When the user clicks the Add To Cart submit button, the form is processed, the properties of CartModifierFormHandler are set, and the handleAddItemToOrder method of CartModifierFormHandler is invoked. The handleAddItemToOrder method iterates through the CartModifierFormHandler.items elements and adds an item for each element quantity, using that element’s productId and catalogRefId for the new item.

The CartModifierFormHandler must be told how many elements to allocate for the items array. This is done by setting the CartModifierFormHandler.addItemCount property.

Overriding the Default Commerce Item Type
By default, Oracle ATG Web Commerce supports three types of commerce items. One corresponds to regular SKUs. The other two correspond to configurable SKUs and their subproperties

The commerceItemType property of CartModifierFormHandler determines what type of commerce item is created by addItemToOrder. Normally, commerceItemType is set to “default.” You can specify a different commerce item type in the CartModifierFormHandler configuration file or in a form input field. If you add multiple items in a single form submission, you can override the CartModifierFormHandler.commerceItemType setting for an individual item by including a hidden input field to set CartModifierFormHandler.items[n].commerceItemType.

Values for commerceItemType must match keys in /atg/commerce/order/OrderTools.commerceItemTypeClassMap.

The CartModifierFormHandler.addItemToOrder method has built-in support for some types of commerce item extensions. If your sites have extended commerce items with primitive data type properties, you can supply values for those properties by associating form fields with the CartModifierFormHandler.value Dictionary.

Removing Items from the Shopping Cart
The CartModifierFormHandler.deleteItems method deletes items that have their CommerceItemIds in the RemovalCommerceIds array. The quantity of the line item that contains the removal request is compared with the total quantity of the commerce item on the page. If the quantities match, the CommerceItemIds is kept in the RemovalCatalogRefIds array to be removed from the page. If the quantities do not match, the system adjusts the quantity accordingly and removes the CommerceItemId from the RemovalCommerceIds array.

Before the deleteItems method removes all items with IDs in the removalCommerceIds array, it runs the prepareLineItemsForRemoval method to return the valid array of IDs to remove, as well as verify if the IDs require partial or complete removal. The prepareLineItemsForRemoval method populates the removalLineItem map that contains a set of IDs and reduction-quantity. The reduction-quantity is subtracted from the original quantity to provide the new quantity available in the shopping cart. Once the deleteItems method removes the necessary elements, it processes the removalLineItems map to adjust the quantities of items that were partially removed.

Adding Shipping Information to Shopping Carts
Creating a list of shipping groups for potential use in the current order. The user can select from among these shipping groups when checking out the order.
  1.     Specifying the shipping groups to use with the current order.
  2.     Selecting the shipping methods, such as Ground or Next Day, for the order’s shipping groups.
ShippingGroupFormHandler form handler and AvailableShippingMethods servlet bean, do not re-price a given Order. Consequently, if you enable customers to make order changes that affect order price through either mechanism, you should reprice the given Order using the RepriceOrderDroplet servlet bean before displaying its price to the customer.

If an order contains any gift items, ShippingGroupDroplet and ShippingGroupFormHandler treat those items and their shipping information differently from other items.

Creating Potential Shipping Groups

Shipping groups for potential use in an Order in one of two ways:
  1.     from information gathered from the user via forms
  2.     from information stored in the user’s profile
To create shipping groups from information obtained from the user via forms, use CreateHardgoodShippingGroupFormHandler and CreateElectronicShippingGroupFormHandler. These form handlers create, respectively, hard good and electronic shipping groups. Additionally, if the addToContainer property of the form handlers is set to true (which it is by default), they add the new shipping group to the ShippingGroupMapContainer and make it the default shipping group in the container. The ShippingGroupMapContainer stores the shipping groups available for use in the current order. Once the shipping group is added to the ShippingGroupMapContainer, the user can use it when checking out the current order.

Adding Payment Information to Shopping Carts

Adding payment information to shopping carts involves the following sub-processes:
  1. Creating a list of payment groups for potential use in the current order. The user can select from among these payment groups when checking out the order.
  2. Specifying the payment groups to use with current order.

Creating Potential Payment Groups

You can create a list of payment groups for potential use in an Order in one of two ways:
  1.     from information gathered from the user via forms
  2.     from information stored in the user’s profile
To create payment groups from information obtained from the user via forms, use CreateCreditCardFormHandler and CreateInvoiceRequestFormHandler. These form handlers create, respectively, CreditCard and InvoiceRequest payment groups. Additionally, if the addToContainer property of the form handlers is true (which it is by default), they add the new payment group to the PaymentGroupMapContainer and make it the default payment group in the container. The PaymentGroupMapContainer stores the payment groups available for use in the current order. Once the payment group is added to the PaymentGroupMapContainer, the user can use it when checking out the current order.

Repricing Shopping Carts

Adding Items to Shopping Carts, CartModifierFormHandler automatically reprices a shopping cart when it is used to add items to the cart. (Note that it also reprices the cart when it is used to remove items from the cart.)

However, you’ll need to reprice shopping carts via some other mechanism if customers can make changes that affect order price through other form handlers that do not reprice shopping carts (for example, by making shipping changes via the form handlers that create and manage shipping groups), or if the shopping carts are modified through some other means in ways that affect order price, such as the delivery of a promotion via a scenario.

Any pages where you need to reprice a shopping cart, but you cannot do so through a form action and corresponding handle method, use the RepriceOrderDroplet servlet bean. In fact, you can use the RepriceOrderDroplet servlet bean to reprice a customer’s shopping cart every time the customer accesses a shopping cart page. This ensures that the customer always views accurate pricing information as he or she makes changes to cart.

The RepriceOrderDroplet servlet bean takes one required input parameter, pricingOp, that should be set to the pricing operation to execute. The possible pricing operations are defined in atg.commerce.pricing.PricingConstants, and they include the following:

    ORDER_TOTAL
    ORDER_SUBTOTAL
    ORDER_SUBTOTAL_SHIPPING
    ORDER_SUBTOTAL_TAX
    ITEMS
    SHIPPING
    ORDER
    TAX
    NO_REPRICE

Typically, the pricingOp input parameter is the only parameter you need to specify when using RepriceOrderDroplet.

<dsp:droplet name="RepriceOrderDroplet">
  <dsp:param value="ORDER_SUBTOTAL" name="pricingOp"/>
</dsp:droplet>


Saving Shopping Carts

SaveOrderFormHandler to save the user’s current shopping cart, add the shopping cart to the user’s list of saved carts in ShoppingCart.saved, and construct a new, empty cart as the user’s current shopping cart in ShoppingCart.current.

Additionally, you can use the description property of SaveOrderFormHandler to set the description property of the Order; this enables users to name their shopping carts with meaningful names. If the user doesn’t provide a descriptive name, then the SaveOrderFormHandler automatically creates one using the user’s locale and the current date and time.

The following JSP code illustrates the use of SaveOrderFormHandler.

<dsp:importbean bean="/atg/commerce/order/purchase/SaveOrderFormHandler"/>

Order # <dsp:valueof bean="ShoppingCart.current.id"/>
  <dsp:form action="saved_orders.jsp">
    Enter a name to identify this order:<p>
    <dsp:input bean="SaveOrderFormHandler.description" type="text"/>
    <dsp:input bean="SaveOrderFormHandler.saveOrder" value="Save order"
         type="submit"/>
    <dsp:input bean="SaveOrderFormHandler.saveOrderSuccessURL"
         value="../user/saved_orders.jsp" type="hidden"/>
    <dsp:input bean="SaveOrderFormHandler.saveOrderErrorURL"
         value="../user/save_order.jsp" type="hidden"/>
  </dsp:form>

ATG IsEmpty, Switch OOTB servlet bean usage

IsEmpty
The IsEmpty servlet bean is very useful in ATG world where we have to render content conditionally based value for bean.

/atg/dynamo/droplet/IsEmpty

The IsEmpty servlet bean conditionally renders one of its open parameters based on the value of its value input parameter. If value is null or if the object is empty, then the output parameter true is rendered. Otherwise, the output parameter false is rendered.

This example displays the a user’s hobbies, using the ForEach servlet bean to render them. If a user identifies no hobbies, a message displays:

<dsp:droplet name="IsEmpty">
   <dsp:param name="value" bean="MyProfile.hobbies"/>
   <dsp:oparam name="false">
      Your hobbies are:
        <dsp:droplet name="ForEach">
           <dsp:param name="array" bean="MyProfile.hobbies"/>
           <dsp:oparam name="output">
              <dsp:valueof param="element"/>
           </dsp:oparam>
        </dsp:droplet>
   </dsp:oparam>
   <dsp:oparam name="true">
      All work and no play makes Jack a dull boy.
   </dsp:oparam>
</dsp:droplet>

Switch
Displays one of several possible outputs, depending on input parameter value. The test value used to determine which output parameter to execute. The Switch value is turned into a string and used as the name of the parameter to render.

/atg/dynamo/droplet/Switch


Switch conditionally renders one of its open parameters based on the value of its value input parameter. This value is turned into a string and used as the name of the parameter to render for this case. You can use Switch to compare two dynamically defined values by setting the name of one open parameter to one value and the Switch servlet bean’s value parameter to the other.


This example outputs a row in a table that lists the person’s name, skill level, and whether the person has a car. Depending on the value of the person.hasCar parameter, Switch displays the capacity of the person’s car.

A second use of Switch outputs 1 person if the car capacity is one, and n people if the car capacity is a different value.

<dsp:importbean bean="/atg/dynamo/droplet/Switch"/>
<tr>
  <td valign=top><dsp:valueof param="person.name"/></td>
  <td valign=top><dsp:valueof param="person.skillLevel"/></td>
  <td valign=top>
    <dsp:droplet name="Switch">
      <dsp:param name="value" param="person.hasCar"/>
      <dsp:oparam name="false">
        none
      </dsp:oparam>
      <dsp:oparam name="true">
        can carry
      <dsp:valueof param="person.carCapacity"/>
        <dsp:droplet name="Switch">
          <dsp:param name="value" param="carCapacity"/>
          <dsp:oparam name="1"> person</dsp:oparam>
          <dsp:oparam name="default"> people</dsp:oparam>
        </dsp:droplet>
      </dsp:oparam>
    </dsp:droplet>
  </td>
</tr>

/atg/commerce/catalog/SKULookup
/atg/dynamo/droplet/Switch
/atg/commerce/ShoppingCart
/atg/dynamo/droplet/Range
/atg/dynamo/droplet/ForEach
/atg/dynamo/droplet/IsEmpty

ATG Custom Catalog

ATG commerce catalog can be customised in customCatalog.xml. All custom repository is defined in this xml file. To access respository ATG provides CustomCatalogTools OOTB class which is an extension of atg.commerce.catalog.CatalogTools that modifies the behavior so it works with custom catalogs.

This class has many methods, which can be used for:
findProduct
findSKU
findCatalogItem
etc...

public class CustomCatalogTools
extends CatalogTools
implements atg.commerce.catalog.CMSConstants

$class=atg.commerce.catalog.custom.CustomCatalogTools
 transactionManager=/atg/dynamo/transaction/TransactionManager
 profileCatalogPropertyName=catalog

 categorysInfosMapProperty=categoryInfos
 productsInfosMapProperty=productInfos
 skusInfosMapProperty=skuInfos

 catalogsProperty=catalogs

 baseCatalogItemType=catalog
 catalogItemTypes=catalog

 catalogProperties=/atg/commerce/catalog/custom/CatalogProperties

 trackState=true

The component /atg/registry/ContentRepositories/ProductCatalog/  has OOTB entry for customCatalog.xml

definitionFiles
CONFIGPATH filename:  /atg/commerce/catalog/custom/customCatalog.xml
CONFIGPATH filename:  /atg/commerce/pricing/pricingModels.xml

The customCatalog.xml can be further customized to have multiple customCatalog.xml file from multiple project in atg layering structure

/atg/commerce/order/OrderRepository/
definitionFiles
CONFIGPATH filename /atg/commerce/order/orderrepository.xml

/atg/commerce/inventory/InventoryRepository/
definitionFiles
CONFIGPATH filename /atg/commerce/inventory/inventory.xml

/atg/commerce/invoice/InvoiceRepository/
definitionFiles
CONFIGPATH filename /atg/commerce/invoice/invoiceRepository.xml

/atg/registry/ContentRepositories/MediaRepository/
definitionFiles
CONFIGPATH filename /atg/content/media/media.xml

/atg/userprofiling/ProfileAdapterRepository/
definitionFiles
CONFIGPATH filename /atg/userprofiling/userProfile.xml

pricingModel.xml contains the promotion specific extensions to product catalog. OOB this is used as one of the constituting ProductCatalog repository definition files but if you want to separate out your promotions repository you can remove it from ProductCatalog repository definition files and instead specify it as repository definition for /atg/commerce/pricing/Promotions.

catalogMigration.xml is defined within DCS.CustomCatalogMigration sub-module and is used while migrating a standard catalog to custom catalog. You are seeing it because you may have included DCS.CustomCatalogMigration while assembling your application.

Some common syntax mostly used:
CustomCatalogProperties catalogProperties = (CustomCatalogProperties) getCatalogTools().getCatalogProperties();
List<RepositoryItem> product = getCatalogTools().findProduct(productId);
String productType = (String) getCatalogTools().getPropertyValueFromRepositoryItem(product,"TYPE");

List<RepositoryItem> skus = (List<RepositoryItem>) product.getPropertyValue(catalogProperties.getChildSkusPropertyName());
String color = sku.getPropertyValue(catalogProperties.getSkuColorPropertyName());
RepositoryItem defaultColorItem = (RepositoryItem) sku.getPropertyValue(catalogProperties.getColorPropertyName());

Condition to check the typed property:
catalogProperties.getSkuAccessoryPropertyName().equals(sku.getPropertyValue(catalogProperties.getTypePropertyName
()))
sku-type
type


<item-descriptor name="sku-type" display-property="displayName" display-name-resource="itemDescriptorSku"
        super-type="sku" sub-type-value="sku-type" cache-mode="simple">

Get sku for product id
RepositoryItem skuItem = getCatalogTools().getProductBySku(pItem.getRepositoryId(), "product");

Get product repository from sku

RepositoryItem prodItem = getCatalogTools().getItem(skuItem.getRepositoryId(), "product");

get brand repository from product repository item

RepositoryItem brandItem = (RepositoryItem)prodItem.getPropertyValue("brandItem");

Get brand name from brand repository item

String brandNameSor = (String) brandItem.getPropertyValue("brandName");

get repository item
RepositoryItem customSellerItem = (RepositoryItem)getCustomSellerRepository().getItem(pItem.getRepositoryId(),"customSeller");

Get the repository item from respository xml
RepositoryItem item = getCustomContentRepository().getItem(productId, catalogProperties.getCustomContentItemDescriptorName());

Read the data from table:
Object obj = getCatalogTools().getPropertyValueFromRepositoryItem(item, catalogProperties.getCustomContent());

Remove item:
getCustomContentRepository().removeItem(productId,"content");

Create Item:
MutableRepositoryItem reviewItem = getCustomContentRepository().createItem
(catalogProperties.getCustomContentItemDescriptorName());

Add item row:
getBvReviewContentRepository().addItem(customItem);

Jsp syntax to get all child SKU IDs of given product id

<dsp:droplet name="/atg/commerce/catalog/ProductLookup">
     <dsp:param name="id" value="ProductId" />
<dsp:oparam name="output">
<dsp:droplet name="/atg/dynamo/droplet/ForEach">
<dsp:param name="array" param="element.childSKUs"/>
<dsp:param name="elementName" value="sku"/>
<dsp:oparam name="output">
Sku Id: <dsp:valueof param="sku.repositoryId"/>
</dsp:oparam>
</dsp:droplet>
</dsp:oparam>
</dsp:droplet>

Syntax in java
StoreCatalogTools storeCatalogTools = (StoreCatalogTools) getCatalogTools();
Repository productCatalog = (Repository) storeCatalogTools.getCatalog();
RepositoryItem productItem = productCatalog.getItem(productId,"product");
List<RepositoryItem> skuList = productItem.getPropertyValue("childSKUs");
for(RepositoryItem sku : skuList){
String id = sku.id();
}

VZWCommonRepositoryInventoryManager

RepositoryItem skuItem = getCatalogRefItem(skuId);
String    itemFulfillmentStatus = getRepository().getItem(inventoryId, getItemFulfillmentStatusItemName());

HTTP request via proxy server

In some cases, we are not allowed to make direct http call to fetch the content.This is due to firewall or org policy. In this case we need to find a way to access outside server via proxy.

Here I am talking about making http call via proxy settings. In this implementation, we need few class to be imported for apache and java net:

import org.apache.http.HttpHost;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.fluent.Request;
import org.apache.http.client.utils.URIBuilder;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.sql.Timestamp;
import java.util.Date;

First step is to create url where we need to connect to access the content:
  String path = "test.htm";
  URIBuilder builder = new URIBuilder();
  builder.setScheme("http").setHost("www.google.com").setPath(path);
  URI targetUrl = builder.build();
Result:  http://www.google.com/test.htm

Second step is to create proxy server:
HttpHost proxy = new HttpHost("proxy.server.com", "1234", "http");
Result:  http://proxy.server.com:1234

Final step is to make http request call get to access content:

String content = Request.Get(targetUrl).viaProxy(proxy).connectTimeout("2000").socketTimeout("3000").execute().returnContent().asString();
           

ATG CommerceItemManager, SimpleOrderManager & OrderManager

OrderManager class is the business layer object for managing and manipulating Orders. This class holds all the business logic for manipulating an Order. The various types of methods in this class are used for creating objects, adding objects to an Order, adding objects to other objects, removing objects from other objects. Below is an example of creating an Order, adding CommerceItems to it, assigning those items to a ShippingGroup and checking the Order out.

 OrderManager om = getOrderManager();
 CommerceItemManager cm = getCommerceItemManager();
 PricingTools pt = getPricingTools();
 String profileId = "10000";
 String catalogRefId1 = "sku-1";
 String catalogRefId2 = "sku-2";
 String productId1 = "product-1";
 String productId2 = "product-2";
 long quantity1 = 1;
 long quantity2 = 2;

 // create the Order and CommerceItems. The Order has a ShippingGroup and PaymentGroup
 // in it when constructed
 Order order = om.createOrder(profileId);
 CommerceItem item1 = om.createCommerceItem(catalogRefId1, productId1, quantity1);
 CommerceItem item2 = om.createCommerceItem(catalogRefId2, productId2, quantity2);

 // add the items to the Order, set the return value back to the object because if the
 // item catalogRefId already existed in the Order, the quantity is incremented rather
 // than adding the new object
 item1 = cm.addItemToOrder(order, item1);  // CommerceItemManager cm
 item2 = cm.addItemToOrder(order, item2);

 // get the ShippingGroup and add the items to it
 ShippingGroup sg = (ShippingGroup) order.getShippingGroups().get(0);
 om.addItemQuantityToShippingGroup(order, item1.getId(), sg.getId(), quantity1);
 om.addRemainingItemQuantityToShippingGroup(order, item2.getId(),sg.getId());

 // add the entire order amount to the PaymentGroup
 PaymentGroup pg = (PaymentGroup) order.getPaymentGroups().get(0);
 om.addRemainingOrderAmountToPaymentGroup(order, pg.getId());

 // Compute the prices using pricing tools
 pt.priceOrderTotal(order);

 // checkout the Order and iterate through the result object displaying errors
 PipelineResult pr = om.processOrder(order);
 if (pr.hasErrors()) {
   Object[] keys = pr.getErrorKeys();
   for (int i = 0; i < keys.length; i++)
     System.out.println(pr.getError(keys[i]));
 }


SimpleOrderManager extends OrderManager. By default, a SimpleOrderManager object is configured in Nucleus at /atg/commerce/order/OrderManager. Logically, the SimpleOrderManager sits above the OrderManager and provides higher-level functionality. What takes several lines of code to do in the OrderManager takes only a single line of code in the SimpleOrderManager. You can use SimpleOrderManager in place of OrderManager to simplify your code, as the example below shows.

String skuId = getSkuId();
String productId = getProductId();
long quantity = getQuantity();
ShippingGroup shippingGroup = getShippingGroup();

getSimpleOrderManager().addItemToShippingGroup(order, skuId, productId, quantity,
                                               shippingGroup);
                                             

This class is the business layer object for Order manipulation. Use of this class eliminates the need to know about Relationships and only requires basic knowledge of the commerce class hierarchy. Logically, this class is one level above the OrderManager class and attempts to do as much as possible for the user. The methods in the class allow CommerceItems to be added to or removed from an Order and ShippingGroup with a single call. It also allows movement of CommerceItems between ShippingGroups.

 Below is an example of using the SimpleOrderManager.

OrderManager om = getOrderManager();
String profileId = "10000";
String catalogRefId1 = "sku-1";
String catalogRefId2 = "sku-2";
String productId1 = "product-1";
String productId2 = "product-2";
long quantity1 = 1;
long quantity2 = 2; // create the Order. The Order has a ShippingGroup and PaymentGroup in it when // constructed Order order = om.createOrder(profileId); // get the ShippingGroup and add the items to it ShippingGroup sg = (ShippingGroup) order.getShippingGroups().get(0);
item1 = om.addItemToShippingGroup(order, catalogRefId1, productId1, quantity1, sg.getId());
item2 = om.addItemToShippingGroup(order, catalogRefId2, productId2, quantity2, sg.getId()); // checkout the Order and iterate through the result object displaying errors
PipelineResult pr = om.processOrder(order);
if (pr.hasErrors()) {
Object[] keys = pr.getErrorKeys();
for (int i = 0; i < keys.length; i++)
System.out.println(pr.getError(keys[i]));
}


ATG IdGenerator logic

The id generator can be configured in idspaces.xml for component atg\dynamo\service.

<id-space name="orderId" seed="200" batch-size="100" prefix="PKP"/>

The IDGenerators execute as follows:

1. When the first IdGenerator starts, it performs the following tasks:

  1. Consults the IdSpace.
  2. Starts with the seed ID and reserves all IDs that start with the seed, up to the batch size, 100.
  3. Sets the value in the ID generator database table to 101. UPDATE SEED COLUMN
2. When the second IdGenerator starts, it performs these tasks:

  1. Consults the ID generator table and finds that the first available ID is 101.
  2. Reserves all IDs from 101 to 200
  3. Sets the value in the ID generator database table to 200.UPDATE SEED COLUMN.


3. When each IdGenerator exhausts its supply of reserved IDs, it returns to the ID generator table and reserves another batch of IDs. It does not need to consult with other IdGenerators to guarantee that its reserved IDs are unique.

IdGenerators and IdSpaces

Dynamo IdGenerator services use the concept of ID spaces. IDs generated by an IdGenerator are guaranteed to be unique within a named ID space. This enables you to have distributed IdGenerator components that share an IdSpace, ensuring that two different IdGenerator components do not use the same ID. When an IdGenerator starts up, it initializes one or more IdSpaces for use by applications.

The examples in theUsing IdGenerators section describe ways to create an IdSpace programmatically. An IdSpace can also be configured with an XML file. The location of the XML file is specified by an IdGenerator component’s initialIdSpaces property. For example, the SQLIdGenerator uses:

initialIdSpaces=/atg/dynamo/service/idspaces.xml

Each IdSpace is defined in the XML file with an <idspace/> tag. The <idspace/> tag has the following attributes:

Attribute Name
Description
Default
name
A string that uniquely identifies an IdSpace within an IdGenerator. An IdGenerator can refer to an IdSpace using this name.
none
seed
The first ID in the space to reserve.
1
batchsize
How many IDs to reserve at a time.
100000
prefix
A string to prepend to the beginning of all string IDs generated from this IdSpace.
null
suffix
A string to append to the end of all string IDs generated from this IdSpace.
null

 If you want to define additional IdSpaces, it is best not to modify the XML configuration file at <ATG9dir>/DAS/config/atg/dynamo/service/idspaces.xml. Instead, create your own XML file of the same name in your localconfig directory and let Dynamo’s XML combination facility combine the files. Note, however, that the idspaces.xml file is read only when the das_id_generator database table is empty. If the das_id_generator table is already populated when you add a new IdSpace to the XML file, your changes are not picked up. As a workaround, manually add the IdSpace with the desired prefix to the das_id_generator table before trying to use that IdSpace.

Important: In general, you should not delete IdSpace rows from the das_id_generator table; doing so can cause ID collisions if an application attempts to use the deleted IdSpace. If you are certain that an IdSpace is never used again, it is safe to delete it.