How to submit a form to Hybris from external application

Gate crash is embarrassing, back door entry is risky. Great is to be welcomed by a friend inside the party, when you are not invited.

Recently, i came to a situation, where i wanted to submit a form to hybris from a application. I thought it would be easy, and all i need is to do a post to a URL.

Booom. It came out with a flat Bad or missing csrf value error.

Once i thought, perhaps i am trying to breach the hybris security. Since there is a contract between client (browser) and the server (hybris) to exchange information. To keep this information just between them, a shared private token is used. This token, known as csrf token, is bound to a session.

@sumitg88 talked about it one of his blog.

Bypassing a request from security layer is one thing. What i wanted was to go through the security layer, and still be able to submit a form, from outside the spring context of Hybris storefront.

I created an API in storefront, which can pass a csrf-token for the current session. The current session can be opened by application, by hitting the home page, may be in an iframe, or through a java program in backend.

Hybris forcefully adds a csrf token inside a hidden field, in every spring mvc form. You can see this happening by going to html source of a page with form. This token is actually validated against the session token to allow a request to pass to the services.

hiddenFields.put(CSRFTokenManager.CSRF_PARAM_NAME, CSRFTokenManager.getTokenForSession(request.getSession()));

In Html forms you can see:

      <input type="hidden" name="CSRFToken" value="0b4eefff-1a05-4bdb-843a-fa9598633dab">

Our API could give the same csrf token, which we can pass through our form in external application. This way, Hybris will take this request as a valid one, and we can submit the form.

The API could look like below:

      public static String getTokenForSession(final HttpSession session)
	{

		// cannot allow more than one token on a session - in the case of two requests trying to
		// init the token concurrently
		Enumeration<String> enumeration=session.getAttributeNames();
		String csrfTokenAttr=null;
		String token=null;
		while(enumeration.hasMoreElements())
		{
			String attrName=enumeration.nextElement();

			if (attrName.contains("CSRFTokenManager.tokenval"))
			{ 
				csrfTokenAttr=attrName;
			}
		}
		synchronized (session)
		{
			token = (String) session.getAttribute(csrfTokenAttr);
			if (null == token)
			{
				token = UUID.randomUUID().toString();
				session.setAttribute(csrfTokenAttr, token);
			}
		}
		return token;
	}

Once you have a valid token, from one of the session, you can submit any form smoothly.

Enjoy!!!!

Hot Deployment – Hybris

Introduction

In this tutorial I will be covering the configuration of JRebel with Hybris. With JRebel configured you will be able to modify java source classes and compile them on the fly.

“No need to build and start the server again and again”

The configuration is very simple, just 3 steps and you are good to go!

Step 1

  • Download JRebel: Archive can be downloaded from the below link http://zeroturnaround.com/software/jrebel/download/prev-releases/
  • Extract the zip file at a location of your preference, for eg: C:/jrebel
    unzip
  • Active JRebel:
    – Go inside bin folder of JRebel.
    – Start the activation utility by running “activate-gui.cmd” file.
    – It will open a Jrebel activation window. The window will contain 2 tabs:
    Try JRebel    for free and I already have a license.Choose Try JRebel for FREE and fill the basic information.

jrebelfreeform
OR
Buy a license and fill the information in the I already have a license section.

Step 2

  • Add the below given property in local.properties file
    tomcat.javaoptions=-agentpath:C:/jrebel/lib/jrebel64.dll
    ** change the version of the jrebel[XX].dll according to the machine specifications.

 Creation of rebel.xml file:
– You will be required to add the rebel.xml file in the resource folder of each extension.

rebel.png

– Create a new rebel.xml class and copy/paste the below given content into the file:

<?xml version=”1.0″ encoding=”UTF-8″?>
<application xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance&#8221; xmlns=”http://www.zeroturnaround.com&#8221; xsi:schemaLocation=”http://www.zeroturnaround.com http://update.zeroturnaround.com/jrebel/rebel-2_1.xsd”&gt;
<classpath>
<!– Make sure to replace Absolute_Path with your concrete values –>
    <dir name=”{Absolute_Path}/classes”/>
</classpath>
</application>

**   The absolute path should be the complete path to the classes folder.
Example: C:/hybris/bin/custom/demo/demofacades/classes

***The classes folder is the compiled source folder of Hybris and not IDE’s(eclipse).

Step 3

  • Change the IDE(eclipse) compile output path in “.classpath” file of the extension.classpath.png
    TO
    classpath1.png
    Path structure:
    path.png
    All the configurations are completed.You just need to recompile the code from IDE(eclipse) after making the changes in the Java source file.For Eclipse you need to do the below mentioned step:

    • Just go to Project -> Clean
    • Select “Clean projects selected below” option and select the extensions which contains the modified java source classes.
    • Select “Start build immediately”.
    • Select “Build only the selected projects”.
    • Press OK and you are done!

Load balancing configurations for SAP Hybris

As mentioned in one of my previous post if not setup correctly clustered environment can be a nightmare. Below are some of the configurations worth noting beforehand:

Server Affinity: a lost session

An HTTP (s) session should always be served by only one SAP Hybris application server otherwise session will be lost and user would need to re-login, even worse anonymous user will lose his cart and all other settings. To avoid this embarrassing experience, enable Sticky Session at application load balancing layer which will stick one session to one SAP hybris server.

Redirect rules: 

Very often redirect rules are defined at load balancing layer to redirect complete URL (base + context )-e.g. http://doodle.com/fun to base URL  e.g. http://doodle.com.

Here one exception should be medias because their urls are appended with /medias at end of base URL and redirecting these URLs to base URL wont load medias:

eg. a call to medias URL –  e.g. http://doodle.com/medias/abc/456789.jpg will be replace with http://doodle.com which will fail loading of medias into SAP Hybris applications.

 

 

Production Infrastructure for SAP Hybris

What is an ideal production server setup? How many servers, cores or nodes do you or customer need?

A production system should not be “it works” but it should be a full-fledged performance setup.

The production setup really varies from customer to customer but in general: one BackOffice server with couple of storefront servers along with webservers, solr servers and a load balancer is very standard infrastructure.

prod-setup

Measurement Metric:

Hybris gauges its performance with page impressions/ second/ core. Standard hybris accelerator comes with a ballpark 10-15 page impressions/second/core. Here fun part is – most of projects start with 1-2 pi/s/core and there can be seriously optimized applications where >50 pi/s/core can be found.

So it’s advised to analyse customer’s requirements with representative data rather than proposing a typically standard infrastructure setup.

 

 

 

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;;;

Relative URLs in Hybris Cockpits

Very often in several business scenarios it is required to share direct Urls of order, cart or product with internal teams, e.g.:

After order is placed:

  • Send confirmation email to customer.

And

  • Also send email to a team of internal staff with direct URL of that order so that staff can directly go to that specific order just by clicking on URL rather than logging into cockpit and searching for that order.

Considering different nature of cockpit framework it’s not straight to create direct URL of an item as compared to storefront which is MVC.

Here is solution:

https://<hostname>:<port>/cscockpit/index.zul?persp=cscockpitPerspective&events=activation&act-item=8796093055021

Understanding URL:

A request event handler parses request parameters and dispatches a Cockpit business event. Different components are then notified of this dispatched event.

According to above URL, Activation request events is triggered for order item with pk – 8796093055021

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>
 

 

 

B2B with B2C – a perfect blend of accelerators (storefronts)

One Hybris – One Accelerator – B2B and B2C – a vision few years ago has been implemented and is at its best now.

There was always need of a blend of B2B and B2C where a B2C customer might have requirement of small organisations concept(B2B units) or a B2B customer might expect a little more from promotions.

B2B features are now available across all Accelerators: in B2C accelertor  -Business units can be created along with their associated supporting elements, such as cost centers, permissions,budgets, users and user groups.

Additionally, commerceorgaddon and b2bacceleratoraddon are introduced to provide B2B storefront support to default accelerator – empowering single accelerator with all features of B2B and B2C.

Load balancer Redirection issue

In clustered environment it’s very common to terminate SSL at load balancer layer and pass non secure requests to Hybris applications servers.

This brings in some complexities if configuration is not correct.

As hybris servers get http request so in case redirection is required they redirect to same non secure protocol which is then recreated into secure request by rules configured at load balancer layer.

To avoid this unnecessary redirection and other potential session issues you have to configure all application servers to redirect to specific port and name.

Add following attributes to <Connector port=”${tomcat.http.port}” in server.xml files of all servers:

proxyPort=”443″ proxyName=”${proxyName}

proxyName – URL of application e.g. google.com

Setting up ASM (assisted service module ) and facing : “Error creating bean with name ‘getAssistedservicestorefrontBeforeViewHandler’”

Are you facing this exception while setting up Assisted Service Module:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘getAssistedservicestorefrontBeforeViewHandler’: Post-processing of FactoryBean’s singleton object failed; nested exception is org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class com.sun.proxy.$Proxy160]: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Cannot subclass final class class com.sun.proxy.$Proxy160

Solution:

Disable Autoproxy – remove entry “<aop:aspectj-autoproxy />” from assistedservicestorefront-web-spring.xml and restart server.. boom!!

 

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.

Adding a new attribute to edit view area in Product Cockpit.

I was working on a Project and there was a requirement to add a new attribute in edit view area In Product Cockpit.

I followed these few step to do this task.

1.Create a new Model e.g MyProduct that extends ProductModel in Items.xml, add attribute in this model e.g:

“<itemtype code=”MyProduct” extends=”Product”>
<description>my product that contains additional attributes.</description>
<attributes>
<attribute qualifier=”attribute1″ type=”localized:java.lang.String”>
<description>example for product cockpit</description>
</attribute>
</attributes>
</itemtype>”

after this,Build the project and start the server, do Update running system from Hac.

Add some product in your “Myproduct” Model.

2.Create  a editorArea_MyProduct.xml file in your Cockpit extension and add key for new attribute in xml file

editorArea_MyProduct

3. Localized the key name in  ProjetcNamecockpits-locales_en.properties and i3-label.properties file.

ProjetcNamecockpits-locales_en

 

4.Restart the server and do update from HAC. Open ProductCockpit in url “http://localhost:9001/productcockpit&#8221; and search your product which you added in “MyProduct” model .

5.Open that product and in left side you will find your new attribute in Editor_area.

Capture1

Error submitting a form due to Cross Site Request Forgery (CSRF)

Recently I faced a problem when I was trying to simply create a Form and a Controller to accept the values submitted from the form. I was using Hybris 5.7 version.

When I entered and submitted some values in the form (or even submitting an empty form) I was continuously getting the following error in the browser and the program control was not reaching my controller:

http status 403 bad or missing CSRF value

After doing lot of googling I found that the above error was coming while sending a “POST” request from any Form and was due to the interceptor “csrfHandlerInterceptor” configured in spring-mvc-config.xml of my storefront. This interceptor is configured to prevent Cross Site Request Forgery (CSRF).

Now to fix this error, there are 2 options:

  1. either the CSRF token in the request matches the session CSRF token to ascertain the validity of incoming posts requests.
  2. or the requested URL is a trusted path and is allowed to go through without CSRF token validation

For the 1st point you need to configure and send a valid CSRF token in your request. You can find information regarding this at: http://docs.spring.io/spring-security/site/docs/3.2.0.CI-SNAPSHOT/reference/html/csrf.html

For the 2nd point you can add your URL entry to “csrfAllowedUrlPatternsList” in your storefront’s spring-mvc-config.xml file as shown below:

<util:list id=”csrfAllowedUrlPatternsList” value-type=”java.lang.String”>
             <value>/upload/createmedia</value>
</util:list>

Please note that for additional details there is a good article on CSRF in Hybris Wiki at the following URL:

https://wiki.hybris.com/display/accdoc/Spring+Security

 

 

Hybris Mobile and Desktop Site

Most people face problem in understanding the difference between Desktop site and Mobile site in Hybris and how do we setup the Mobile site and what parameters control the switching of Desktop and Mobile site. Also, how does a responsive site differ from both Desktop and Mobile site?

Technical Difference in terms of UI

First of all, the mobile site differs from the desktop site generally in terms of the UI. The back end code mostly remains the same for both the mobile and desktop sites.

The UI change is controlled by CSS, JS and images.

Also, the UI, which is defined using Hybris WCMS, need to define different Page Template, ContentSlot, ContentPage, ProductPage and the relationship between them for Mobile site and Desktop site.

Technical Difference in terms of Java code

For accessing the UI of either the Mobile site or the Desktop site, we need set the UiExperienceLevel to corresponding device type for which we need to first of all detect the device from which request is coming. This is done using an interceptor i.e. DeviceDetectionBeforeControllerHandler using class DefaultDeviceDetectionFacade and more specifically in SpringMobileRequestDeviceDataPopulator.

After device detection, the detected device needs to be mapped to a UiExperienceLevel (i.e whether it is desktop, tablet, mobile), which is done in class DeviceDataUiExperiencePopulator.

After this the detected UiExperienceLevel is compared with the supported UiExperienceLevel and if matched then DetectedUiExperienceLevel is set to this value.

Parameters controling switching of Desktop and Mobile site

UiExperienceLevel is configured in your properties file using the property “uiexperience.level.supported”.

Please note the correct format of specifying the value for “uiexperience.level.supported” is comma separated Camel Case names like Mobile,Desktop or Desktop,Mobile for the functionality to work correctly.

There is one more interceptor SetUiExperienceBeforeControllerHandler called before the request reaches the controller. This interceptor checks for the parameter “uiel” (like ?uiel=Mobile) in the request and if set its value is used to override all previous UiExperienceLevel.

Based on the UiExperienceLevel set, the corresponding CSS, JS and images are set and we see either the Mobile site or the Desktop site.

Responsive

When we have constructed our website for Responsive UI then the UI automatically adjusts itself according to the device type and this is done because of the responsive JS used. Hybris has made the desktop site responsive hence eliminating the need for separate Desktop and Mobile sites.

Different Views for Electronics Site:

MobileSite
Mobile Site – Non Responsive
ResponsiveSite-MobileView
Mobile Site – Responsive

 

 

 

 

 

 

 

 

 

ResponsiveSite-DesktopView

Desktop Site – Responsive

ResponsiveSite-TabView

Tab Site – Responsive

 

What are ModelAttributes?

Some time it is necessary to get few data in many JSPs, and we don’t want to pass them as a part of DTO (data objects). For example, the titles (Mr and Mrs etc). They can be used in many JSPs and tags file, like registration, delivery address etc.

In such cases, what we do is, create a convenient method in Abstract controllers, and use model attribute annotation for them. In this way they are available from all JSPs directly  using model attribute.

modelAttributes

These can be accessed directly in JSPs or even tag files. like

Current Language : ${currentLanguage}

Extensions in Hybris

Hybris suite is a package of number of business functionalities, like a storefront to checkout products, a platform to provide spring features, a service layer to provide persistence and lot others.

Each of these functionality is available as an isolated java project, which has it’s own data model (if required), its own spring configurations ans properties etc. This grouping of similar functionality into one java project is termed as extension. Below is a snapshot for commerceservices extension from hybris.

ext1

An extension may or may not have a web interface. It may depend on other extensions to fulfill it’s purpose. This information is defined in extensioninfo.xml

The data model of extension is defined in <extension-name>-items.xml file.

The spring configuration for an extension is defined in <extension-name>-springs.xml. It has all bean definitions, dependency injections etc.

Each active extension of your hybris project must find a place in localextension.xml

storefront

As the name suggests, its the front of a store.

Storefront is basically the front end for your hybris eco system, which is visible to potential customers. They can browse products, categories offered by business. They can contact the business from here. They can order an item or cancel the purchase from here.

The storefront also allows you to search for physical stores present in your area using store locators. User can search for a product and add it his wishlist.

So basically, the store front is the control panel for the customers to get engaged with business in several ways. We normally call it the web site.

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

What is base store?

While designing the data model for a project, we need to represent every physical entity with an online analog. Like for consumers of your products/services, we have Customer.

Here Customer is not just a word in online world. Rather it is an item type, which has its own attributes and data structure, like email, mobile of customer. every thing related to customer will go in a table called Customer.

Similarly, we need to define an online entity to represent the whole business house. This will have all the attributes, related to business, like websites associated with it, all physical stores the product catalogs, currency it operates in, etc.

This entity chosen is Base store.

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.