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

Why models are generated in platform extensions?

Hybris is build over the concepts of extensions. Each extension has it’s own data model. Any extension can use an item type from other extension and extend it as per requirement.

For example, the itemtype  product defined in core extension. The catalog extension has extended the product itemtype, and added vendor to it.

While building the hybris, the frameworks builds according to dependencies. Since core is build before catalog extension, it is not aware of the vendor attribute defined in catalog extension. If we keep model class in extensions, then there will e chance of build failures. Like in our case, vendor attribute will not find a place in ProductModel class.

blog1

Hybris build framework, creates model classes, even before, building any extension. The platform is the best place to keep them, as every extension is built upon it only. So it is not logical to create model classes in particular extensions, when we can define same data model in various extensions.

What are Catalog aware item types?

While creating a data model for your project, you might come across situations, where you might want some of your item types to be part of catalog. This means, you want them to synchronize, you want them to be associated with a catalog, content or product. Such item types are known as catalog aware. It’s not just CMS item types or products, that needs synchronization. All OOB CMS items and products are catalog aware.

To explicitly make an item type to be catalog aware, follow below steps:

  • Mark your item as catalog item type, using custom property catalogItemType.
  • Choose attribute from item, which will qualify the  catalog associated using custom property catalogVersionAttributeQualifier.
  • Since each item in a catalog must be unique, we need to choose an attribute from item which is unique. This can be done using custom property uniqueKeyAttributeQualifier.

<itemtype code=”MyItemType” autocreate=”false” generate=”false”>

        <custom-properties>

            <property name=”catalogItemType”><value>java.lang.Boolean.TRUE</value></property>

            <property name=”catalogVersionAttributeQualifier”><value>”catalogVersion”</value></property>

            <property name=”uniqueKeyAttributeQualifier”><value>”code”</value></property>

        </custom-properties>

        <attributes>

            <attribute qualifier=”catalogVersion” type=”CatalogVersion”>

                <modifiers read=”true” write=”true” search=”true” optional=”false” unique=”true”/>

                <persistence type=”property”/>

            </attribute>

Once updating your item type, you should update your platform, using system update.

And you should see something like below in HMC > System > item types > MyItemType > Extended

1

Now, instances of this itemtype will be catalog aware, and would be part of synchronization.

What does partOf modifier means?

In my school, IT department had 5 professors, who taught different subjects of  computer science. School used to manage departments, and professor used to teach. They had their own work life cycles. Everything was so good. But then, school decided to close the department. The professors were bound to loose their jobs. Since they were part of the department. That’s how life is.

When your object is bound to loose it’s existence, when the parent object cease to exist, we say that, child object must have an partOf modifier attached.

For example, An address object is useless, until it is bound to some User object.

Have you heard of cascade-delete in SQL. It describe the same phenomenon.

<attributes>

            ...

            <attribute autocreate="true" qualifier="addresses" type="AddressCollection">

               <modifiers read="true" write="true" search="false" optional="true" partof="true"/>

               <persistence type="jalo"/>

            </attribute>

Why we have converters and populators in hybris?

I can convert my models to DTO directly in facade layer. Then why should i have a converter?

Its Simple. We may need to convert a product (model) from multiple places. We convert it on product listing page, product detail page, order confirmation page etc. Hybris follows oops concept..So it is good to have a separate class to do this conversion for us, from all of these places.

Converters creates an object of DTO. While populators breaks the code for filling up data in DTO. This is required because, not each DTO needs all attributes of a model. Thus by having multiple populators, we can write more efficient code. Reverse populators are used to fill data in model from DTOs.

blog1

The image shows two paths followed (a and b) by two different facades using same converter and different poplators.

We should always use spring injected converters and  populators.

Addon or Extension?

When it come to choose between addon or extension, it becomes a tricky situation. Because we don’t know actually, which one is preferable over another.

Extensions are basically a collection of related functionality, like we have promotion or a store front. It is a larger artefact, in terms of complexity and purpose it solves.

On the other hand, add ons, as their name suggests, are introduced to garnish a existing functionality. They are like toppings over your meal (extensions). For example, a Captcha addon.

  • When we need a functionality, which is used across multiple store front, like captcha, we can go for a addon. We need not to write a separate extension for that. But we can not go for an addon, if we need multiple sites, for multiple country or language. In that case, we need to create separate extension for that.
  • Suppose, you are working with a legacy system, where you can not modify the code base, but you want to modify the look and feel of it’s store front, in that case we can go for a add on.

How to modify attributes of an item type without system update/initialization?

Often we come across the situation, when it is difficult to run a system update, like in production. But still we need to apply some modification at an attribute level.

Hybris has provided Hybirs management console (HMC) , as a graphical tool, which mirrors database in a user friendly way.

Go to HMC > system > type > Search for your item type > Properties.

Here you can apply all sort of modifications you want to do. You can set default values, initial values, mandatory nature etc.

 

23

 

Why hybris deprecated tenant scope?

To understand, the meaning of tenant scope, see my previous post on scopes in hybris. With version 5.0 , hybris decided to deprecate tenant scope.

In verion 5, Hybris has tenant specific application contexts. So the bean you will get will be singleton by default, which is already limited to a tenant. So there is no need to have a different scope called tenant.

scopes

 

 

As you can see fro above picture, each tenant creates its own set of application context, so now tenant scope is redundant.

Source : Hybris Wiki

What is difference between store and site?

Did you ever wondered why Hybris created two entities, store and site? What is the relation between them? What is the difference between them?

Most of the times, organisations have physical stores, with inventories, catalogs etc. and then they decide to have an online version for everything. Though we have exceptions now a days, where we have direct online stores, like FlipKart. Though they still have to have physical inventories to fulfill orders.

So in a sense, we can say that there are essentially two entities, one could be real (Physical) and another is virtual (Online).

So we can say that store is an entity which is associated with catalogs, stocks, currencies, language etc. The locale is associated here, as it can be looked more tightly coupled with physical analog, who are concrete in nature.

Store.impex sample,

INSERT_UPDATE BaseStore;uid[unique=true];catalogs(id);currencies(isocode);
;$storeUid;$productCatalog,$classificationCatalog;$currencies;

On the other hand, we have site, which corresponds to online entity. The online entities should essentially have URLs, and language associated with them.

Sample site.impex

$siteUid=hybris
UPDATE CMSSite;uid[unique=true];urlPatterns;defaultlanguage(isocode)
;hybris;”(?i)^https?://[^/]+(/[^?]*)?\?(.*\&)?(site=$siteUid)(|\&.*)$,(?i)^https?://$siteUid\.[^/]+(|/.*|\?.*)$,(?i)^https?://api\.hybrisdev\.com(:[\d]+)?/rest/.*$,(?i)^https?://localhost(:[\d]+)?/rest/.*$,(?i)^https?://[^/]*/igcstorefront((?![\?\&]site=).)*,(?i)^https?://.*\.[^/]+(|/.*|\?.*)$”;en

So how do they relate??

Think once. Amazon has many physical stores worldwide. Also it has many sites, based on countries, language etc. So the relation between two is very dynamic. It has to be Many to Many.

That is how it is done in hybris in base commerce items.

<relation code=”StoresForCMSSite” generate=”true” localized=”false” autocreate=”true”>
<deployment table=”Stores4Site” typecode=”1092″ />
<sourceElement qualifier=”cmsSites” type=”BaseSite” cardinality=”many” />
<targetElement qualifier=”stores” type=”BaseStore” cardinality=”many” collectiontype=”list” ordered=”true” />
</relation>

How the online site will look depends on the content, and not what is the price of a product. So content catalog is associated with cms site, not store.

<relation code=”CatalogsForCMSSite” generate=”true” localized=”false” autocreate=”true”>
<deployment table=”Catalogs4Site” typecode=”1063″ />
<sourceElement qualifier=”cmsSites” type=”CMSSite” cardinality=”many” />
<targetElement qualifier=”contentCatalogs” type=”ContentCatalog” cardinality=”many” collectiontype=”list”
ordered=”true” />
</relation>

Hybris could have their own reason to do so. This is what i could envisage from my experience.