Interceptor in SAP Hybris Commerce

Interceptor

An interceptor addresses a particular step in the life cycle of a model. When the life cycle reaches a certain step, you can activate a corresponding interceptor. An interceptor can modify the model, raise an exception to interrupt the current step or publish an event if the model matches certain criteria. For example, you could check that an attribute contains certain values before saving the model.

In easy words, we can say that anything that intercepts something else is called an interceptor. We can take one example to explain interceptor concept in a real-life scenario. We take one example where a person wants to watch a movie in the cinema hall. Now we will see how an interceptor is used in this scenario.

Interceptor Example

In the above diagram, we can see that one person went to the cinema hall and his journey intercepted at the ticket checking counter. Here Diamond(Has ticket) works as an interceptor. If a person has a ticket then he is permitted to watch a movie. If he doesn’t have a ticket then he is redirected to buy a ticket at the ticket counter.

What is the model’s life cycle?

This question is asked in hybris interviews. Here I am trying to explain this so it can help you in cracking hybris interview.

A model represents a state in the database. The representation is not live, that means that modified model values are not written to the database automatically. Instead, when you modify a model, you must explicitly save it to the database to have its state reflected there.

Model Life cycle
Model Life Cycle

Phases in the Model’s life cycle

There are four phases in the model’s life cycle.

  1. Instantiating the model
  2. Modifying model values
  3. Saving Model Values
  4. Removing the model

 

1. Instantiating the model

This can be done by either creating a new Model instance or by loading a Model from the database.

  1. Creating a model instance:- Visit link Model service create method vs new operator.
  2. Loading an existing model from the database is possible either by using pk or by using a query expression.
    Example:- UserModel user = modelService.get(pk);    [loading using primary key]

2. Modifying model values

We can modify the properties of the model if required.

3. Saving model values

If a model is created or modified. We save back the model to update the database. If we have used a new model, a new record is inserted/created in the database, otherwise, the existing record is updated.

4. Removing the model

If the model is no longer needed, the database record is deleted.

We can use interceptors to hook into the model’s life cycle.

Types of interceptors

  1. Load interceptor

    The load interceptor is called whenever a model is loaded from the database. You may want to use this interceptor if you want to change the values of the model after load. An exception raised during execution prevents the model from being loaded. To use this interceptor we must implement LoadInterceptor interface.

  2. InitDefaults Interceptor

    The InitDefaults interceptor is called when a model is filled with its default values. This happens either when it is created via the modelService.create method or when the modelService.initDefaults method is called. You can use this interceptor to fill the model with additional default values defined in the items.xml. To use this interceptor we must implement InitDefaultsInterceptor interface.

  3. Prepare interceptor

    The Prepare interceptor is called before a model is saved to the database before it is validated by Validate interceptors. Use this to add values to the model or modify existing ones before they are saved. An exception is raised during execution prevents the model from being saved. Prepare interceptor is called before the Impex translators. To use this interceptor we must implement PrepareInterceptor.

  4.  Validate interceptor

    The Validate interceptor is called before a model is saved to the database after is been prepared by the Prepare interceptors. We can use Validate interceptor to validate values of the model and raise an InterceptorException if any values are not valid. To use this interceptor we must implement ValidateInterceptor.

  5.  Remove Interceptor

    The Remove interceptor is called before a model is removed from the database. We can use this interceptor to prevent the removal of the model by raising an InterceptorException. To use this interceptor we must implement RemoveInterceptor.

How to register an interceptor?

After implementing an interceptor, we need to register it as a spring bean. The steps involved in registering an interceptor as followed:-

  1. Navigate to  customExtension->resources and open customExtension-spring.xml. Add the following line of code to this file.
    Custom Interceptor Bean
  2. In this step, we will do Interceptor mapping as shown in below image.
    Interceptor Mapping

What are component type group in Hybris?

Not everything is for everyone. This simple law of nature binds everything together. A polar beer is best kept away tropical area. Your business may want to keep only coordinated banners in rotating image banners. The content slots are bounded to have only few type of components to achieve these restrictions.

Components are grouped on basis of their types. These groups are termed as ComponentTypeGroup. There is one to many relations between this group and the components. They are persisted in database. In earlier versions, the valid component list was used just as macro in impex.

This approach is more optimal than the previous one which had a slow many to many relationship between ContentSlotName and Cms Component type.

<relation code="ComponentTypeGroups2ComponentType" generate="true" localized="false" autocreate="true">
			<deployment table="CompTypeGrp2CompType" typecode="1097" />
			<sourceElement qualifier="componentTypeGroups" type="ComponentTypeGroup" cardinality="many" collectiontype="set"/>
			<targetElement qualifier="cmsComponentTypes" type="CMSComponentType" cardinality="many" collectiontype="set"/>
</relation>

There are few groups which are defined in OOB Hybris. We can also define our custom groups.



INSERT_UPDATE ComponentTypeGroup;code[unique=true]
;logo
;headerlinks
;searchbox
;minicart
;wide
;narrow
;footer
;navigation
;mobile

Each valid component type is added to the group.

INSERT_UPDATE ComponentTypeGroups2ComponentType;source(code)[unique=true];target(code)[unique=true]
;narrow;ProductFeatureComponent
;narrow;CategoryFeatureComponent

When a component type is checked against its validity for a given content slot, the system checks if it is contained in the component type group.

INSERT_UPDATE ContentSlotName;name[unique=true];template(uid,$contentCV)[unique=true][default='LandingPage4Template'];validComponentTypes(code);compTypeGroup(code)

;SiteLogo;;;logo
;HeaderLinks;;;headerlinks
;SearchBox;;;searchbox
;MiniCart;;;minicart
;NavigationBar;;;navigation
;Section1;;;wide
;Section2A;;;narrow
;Section2B;;;narrow
;Section2C;;;wide
;Section3;;;wide
;Section4;;;narrow
;Section5;;;wide
;Footer;;;footer
;TopHeaderSlot;;;wide
;BottomHeaderSlot;;;wide
;PlaceholderContentSlot;;;

What is the use ProductOption Enum in Hybris?

Products are core to any commerce. This is the product which drives the whole business and workflow associated with it. Be it procurement, inventory management, Media management, order management, fulfillment to name a few. Everything revolves around Product.

Essentially, this leads to having hundreds of attribute associated with products. Price, Stock , promotion, categories are few data set attached to product. Since not every page will want to have every data set to be populated. This is also not efficient to propagate all data sets to front layer.

Product Option is an Enum, which categorize hundreds of attribute of products into few data sets. For example attribute related to stocks (stock level, stock status) will be under Stock data set. Now the population of Product data will be done on the required data sets of Product Option Enum.

Take the example of Order history page, here we don’t want user to see stock data, product reviews, product delivery modes. So it is useless to populate these data sets.

 

Hybris provides a Bean class DefaultModifableConfigurablePopulator, which takes a Map of populators as one of the property. This map will contain Product Option enum as the key and corresponding populator bean id as the value.

 

<alias name="defaultProductConfiguredPopulator" alias="productConfiguredPopulator"/>
<bean id="defaultProductConfiguredPopulator" class="de.hybris.platform.commercefacades.converter.impl.DefaultConfigurablePopulator" >
<property name="populators">
<map key-type="de.hybris.platform.commercefacades.product.ProductOption">
<entry key="BASIC" value-ref="productBasicPopulatorList"/>
<entry key="PRICE" value-ref="productPricePopulatorList"/>
<entry key="PRICE_RANGE" value-ref="productPriceRangePopulator"/>
<entry key="GALLERY" value-ref="productGalleryPopulatorList"/>
<entry key="SUMMARY" value-ref="productSummaryPopulatorList"/>
<entry key="DESCRIPTION" value-ref="productDescriptionPopulatorList"/>
<entry key="CATEGORIES" value-ref="productCategoriesPopulatorList"/>
<entry key="PROMOTIONS" value-ref="productPromotionsPopulatorList"/>
<entry key="STOCK" value-ref="productStockPopulatorList"/>
<entry key="REVIEW" value-ref="productReviewPopulatorList"/>
<entry key="CLASSIFICATION" value-ref="productClassificationPopulatorList"/>
<entry key="VARIANT_FULL" value-ref="productVariantFullPopulatorList"/>
<entry key="REFERENCES" value-ref="productReferencesPopulator"/>
<entry key="DELIVERY_MODE_AVAILABILITY" value-ref="productDeliveryModeAvailabilityPopulator"/>
</map>
</property>
</bean>

 

If You want to add a new populator to the system, for example say video.

<enum class="de.hybris.platform.commercefacades.product.ProductOption">
<value>VIDEO</value>
</enum>

 

Now redefine the configureable populator bean to include your populator. Now the product data will start having your data set as well.

<alias name="videoProductConfiguredPopulator" alias="productConfiguredPopulator"/>
<bean id="myProductConfiguredPopulator" parent="defaultProductConfiguredPopulator">
    <property name="populators">
        <map key-type="com.myproject.facades.product.MyProductOption" merge="true">
            <entry key="Video" value-ref="videoOptionPopulator"/>
        </map>
    </property>
</bean>
 

 

 

Understanding Spring Events in Hybris

We humans are known to celebrate certain milestones in our life journey. We do celebrate birth, tying knots etc. Similarly, in the buying journey of a customer, there are few milestones which are worth celebrating or react to. Order placement, registration of a customer is few of them. The reaction could be about sending a welcome email, or sending the order data to a third party system for fulfillment.

Further, let’s say, a customer registered on a web site, and wants to start browsing the cool products. But the lousy code of sending a fancy welcome email with a promotional voucher in it, took around one minute. He will regret his decision to register, and will walk away.

spring-listener.jpg

Spring based events, provides the exact same infrastructure. So now we know, whenever we have a situation where some lousy code is to be executed after some thing happens (an event), we will rely on events.

 First we need to create an Event class, that will hold the necessary data to pass to the listener.

protected AbstractCommerceUserEvent initializeEvent(final AbstractCommerceUserEvent event, final CustomerModel customerModel)
{
event.setBaseStore(getBaseStoreService().getCurrentBaseStore());
event.setSite(getBaseSiteService().getCurrentBaseSite());
event.setCustomer(customerModel);
event.setLanguage(getCommonI18NService().getCurrentLanguage());
event.setCurrency(getCommonI18NService().getCurrentCurrency());
return event;
}

Spring provides a way to publish an event.

getEventService().publishEvent(initializeEvent(new RegisterEvent(), customerModel));

There are dedicated listeners lying around, who listens to these wishes, and reacts the way, they are programmed.

Listeners can be bonded to publishing services via common event object.

public class RegisterEventListener extends AbstractEventListener
{
   @Override
   protected void onEvent(final AbstractEvent event)
   {
      if (event instanceof RegisteEvent)
      {
          // Do whatever you want. send email/voucher or whatever
      }
   }
}

Please note that since, listener code starts in a new thread, it will not hamper customer journey on your site. The listener code will execute as a back end process.

How to run multiple hybris instance in one machine?

Basically hybris runs on a tomcat instance. Hybris is shipped with a bundled tomcat. So the question here is actually, how to run multiple tomcat in one machine.

We can run as many hybris we want, till our machine memory permits. To do so, we need to make each instance of tomcat to have it’s own ports to use. Make below ports unique for each instance. We should add below properties in local property file of each instance with unique values..

tomcat.http.port=7001
tomcat.ssl.port=7002
tomcat.ajp.port=7009
tomcat.jmx.port=7003
tomcat.jmx.server.port=7004

Why order is important in items.xml?

We need to follow an order in items.xml, when we declare item types in items.xml. Below are the reasons for it.

  • Each items.xml is parsed in single pass. This means, more specific types are dependent on general types. In such case they should have been defined before we use them. For example,

items

Here we see that, item type product is using other item types, like catalog. To make this file successfully, it is mandatory that catalog exist before product is declared. We must defines types in order of inheritance.

Please note that impex files are parsed in multiple pass, so order is not important there.

  • Each xml file is validated against a items.xsd during build. If the xml file does not conforms to xsd file, build will fail.

What does ATP means in hybris?

ATP – Available to promise.

ATP is an integer, which defines, the number of stock that is available to promise to customer as sell-able. In real life, the stock present in warehouse doesn’t necessarily means that it is the amount, you can sell. this is because

  • Some stock available at a warehouse, when it start operations (after a reconciliation, typically every morning). it is known as Stock on hand (SOH).
  • some stock at a warehouse, may already be ordered, and waiting to be shipped. we can not sell it again. such stock is known as reserved.
  • We may ask for more stock from other partner/warehouse in a timely manner. such stock is called oversell.
  • an order is cancelled. so it would be available again. we need to subtract ordered quantity from reserved.
  • An order is returned. so it would be available again. we need to subtract ordered quantity from reserved.

so we see, there may be many business rules, which may define the ATP level. A typical definition of ATP may be:

ATP = ( SOH + OverSell ) – reserved