0% found this document useful (0 votes)
67 views261 pages

SAP Hybris V6 Certified Development Professional - Study Guide

The SAP Hybris V6 Certified Development Professional Study Guide provides a comprehensive overview of the necessary knowledge and skills for the certification exam, including 170 questions for exam preparation. It covers various topics such as WCMS, backoffice, order management, and platform basics. The guide is authored by Benoit Vanalderweireldt and was published on October 25, 2016.

Uploaded by

aminewiksi
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
67 views261 pages

SAP Hybris V6 Certified Development Professional - Study Guide

The SAP Hybris V6 Certified Development Professional Study Guide provides a comprehensive overview of the necessary knowledge and skills for the certification exam, including 170 questions for exam preparation. It covers various topics such as WCMS, backoffice, order management, and platform basics. The guide is authored by Benoit Vanalderweireldt and was published on October 25, 2016.

Uploaded by

aminewiksi
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 261

SAP H[y]bris V6 Certified

Development Professional
Study Guide

wcms, backoffice, cockpit, accelerator, data model, order,


search, platform, pcm, price, user

170 questions to prepare the final exam!

Benoit
Vanalderweireldt
SAP Hybris V6 Certified Development
Professional | Study Guide

Benoit Vanalderweireldt

2016-10-25
© 2017 Hybhub
© 2014 hybris AG or an SAP affiliate company. All rights reserved. Hybris and
other Hybris products and services mentioned herein as well as their respective
logos are trademarks or registered trademarks of hybris AG (or an SAP affiliate
company) in Switzerland, Germany and other countries. All other product and
service names mentioned are the trademarks of their respective companies. learn
more
Contents

1 Introduction 6
About the author . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
Requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
Groovy console . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
Example Groovy console . . . . . . . . . . . . . . . . . . . . . . . 8
Assessment test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
Questions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
Solutions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

2 WCMS 16
CMS Items hierarchy . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
CMSItem CMSRelation . . . . . . . . . . . . . . . . . . . . . . . 17
CMSItem types . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
CMS Components . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
Example how to create a cms component . . . . . . . . . . . . . 18
Personalization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
Segmentation rules . . . . . . . . . . . . . . . . . . . . . . . . . . 21
Segmentation actions . . . . . . . . . . . . . . . . . . . . . . . . . 22
Create a CMS restriction . . . . . . . . . . . . . . . . . . . . . . 22
WCMS cockpit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
Warehouse & point of service . . . . . . . . . . . . . . . . . . . . . . . 23
Warehouse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
Point of services . . . . . . . . . . . . . . . . . . . . . . . . . . . 24

3 Backoffice & Cockpits modifications 25


Create a new Backoffice application . . . . . . . . . . . . . . . . . . . 25
Create & connect a new widget . . . . . . . . . . . . . . . . . . . . . . 26
Legacy Cockpit modification . . . . . . . . . . . . . . . . . . . . . . . 29

4 Commerce and Accelerator 30


Create New Addon . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
OCC Webservices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
Install OCC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
OAUTH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40

2
Create / customize webservices . . . . . . . . . . . . . . . . . . . 42
CMS navigation bar . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
Order splitting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
Promotion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
Payment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
Internationalization . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
Request handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
Request filters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
Hot folders . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
Create a new import configuration . . . . . . . . . . . . . . . . . 55
Data Modeling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
Create new types . . . . . . . . . . . . . . . . . . . . . . . . . . . 57

5 Order management 88
Business process . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
Fulfillment process . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
Shopping cart handling . . . . . . . . . . . . . . . . . . . . . . . . . . 95
Checkout flow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
ASM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
CS Cocpkit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106

6 Search & navigation 107


Solr index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
Solr Indexed Property . . . . . . . . . . . . . . . . . . . . . . . . 109
Solr Indexed Query . . . . . . . . . . . . . . . . . . . . . . . . . . 112
Solr Search Field . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
Indexing listeners . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
Solr Facet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
Solr Facet Range . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
Auto suggestion & keywords & stopwords & synonyms . . . . . . 116
Hero products & boost rules . . . . . . . . . . . . . . . . . . . . . 118

7 Platform basics 124


Initialization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
Update . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
Update and Initialization lock . . . . . . . . . . . . . . . . . . . . . . . 125
Update and Initialization hooks . . . . . . . . . . . . . . . . . . . . . . 126
Essential & project data . . . . . . . . . . . . . . . . . . . . . . . . . . 128
Import by convention . . . . . . . . . . . . . . . . . . . . . . . . 128
Import by configuration . . . . . . . . . . . . . . . . . . . . . . . 128
Control the order of import . . . . . . . . . . . . . . . . . . . . . 129
Sessions handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
Extensions structures . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
extensioninfo.xml . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
localextensions.xml . . . . . . . . . . . . . . . . . . . . . . . . . . 131
Create a new extension . . . . . . . . . . . . . . . . . . . . . . . . 132
Maven . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
Configuration Service . . . . . . . . . . . . . . . . . . . . . . . . . 134
Environment variables . . . . . . . . . . . . . . . . . . . . . . . . 135
Runtime optional configuration . . . . . . . . . . . . . . . . . . . 135
Build . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
Callbacks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
Tenant . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
Cache . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
Region cache . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
Interceptors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139
Transactions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142
Tasks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142

8 Platform core 144


Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
Impex . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
Header . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
Comment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150
Macro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150
Abbreviations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150
Document ID . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
Translators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
Alternative pattern . . . . . . . . . . . . . . . . . . . . . . . . . . 152
Distributed Impex . . . . . . . . . . . . . . . . . . . . . . . . . . 152
Spring context . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152
Cronjobs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153
Cluster . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
Cache invalidation . . . . . . . . . . . . . . . . . . . . . . . . . . 157
Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157

9 PCM & price 158


Price calculation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158
Taxes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159
Discounts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
Media object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
Media formats and Media container . . . . . . . . . . . . . . . . 161
Media contexts . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162
Secured media . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162
Synchronization jobs . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162
Workflow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163

10 User Management 165


User rights . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165
Access rights . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165
Search restrictions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
Service layer example . . . . . . . . . . . . . . . . . . . . . . . . . 167
Impex example . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168
B2B hierarchy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168

11 Study tips 169


Study plan . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169
Play with SAP Hybris . . . . . . . . . . . . . . . . . . . . . . . . . . . 170
Identify your weakest point . . . . . . . . . . . . . . . . . . . . . . . . 170
Understand the Questions . . . . . . . . . . . . . . . . . . . . . . . . . 170
Checking the answer . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170

12 Mock exam 1 171


Questions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
Solutions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199

13 Mock exam 2 217


Questions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217
Solutions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245
Chapter 1

Introduction

Dear Reader,
Thank you for choosing SAP Hybris V6 Certified Development Professional |
Study Guide to prepare for your SAP certification.
I’d be very interested to hear your feedback on how you are doing after using
this e-book. Feel free to let me know what you think about this study guide by
sending an email to [email protected].
If you disagree or think there are technical errors, feel free to share it with me.

About the author


Benoit Vanalderwireldt has worked as an SAP Hybris developer for the
last 4 years for different companies in Asia, US and Europe. Besides being an
enthusiastic SAP Hybris developer, Benoit loves building software and
infrastructures using automation.
You can learn more about him by visiting his profile on Linkedin : https://www.
linkedin.com/in/benoitvanalderweireldt

Requirements
In order to use this study guide you need :
1. SAP H[y]bris V6.x
2. access to http://help.hybris.com
3. access to http://experts.hybris.com
4. a working IDE compatible with SAP Hybris (Eclipse, IntelliJ, Netbeans…)

6
5. a JDK 8 installed

Groovy console
SAP Hybris commerce has the ability of running a Groovy script on a running
system, from your script you are able to access all services, facades and therefore
items. It makes the groovy console the best place to run any sort of quick tests
or validate a piece of code on SAP Hybris (http://groovy-lang.org).
To run a groovy script open http://localhost:9001/console/scripting/ and select
groovy as script type.
If rollback mode is on, no data would be persisted, so if you want to
manipulate data remember to switch the mode to commit
Example loading a product:
1 import de.hybris.platform.servicelayer.search.FlexibleSearchService
2 import de.hybris.platform.catalog.CatalogVersionService
3 import de.hybris.platform.catalog.model.CatalogVersionModel
4 import de.hybris.platform.core.model.product.ProductModel
5

6 FlexibleSearchService fss = spring.getBean("flexibleSearchService")


7 CatalogVersionService cvs = spring.getBean("catalogVersionService")
8 CatalogVersionModel cvm = cvs.getCatalogVersion("
electronicsProductCatalog","Online")
9

10 ProductModel pm = new ProductModel()


11 pm.setCode("1099413")
12 pm.setCatalogVersion(cvm)
13

14 pm = fss.getModelByExample(pm)
15

16 println pm.getName()
Example Groovy console

Assessment test
When you prepare the P_HYCD_60 exam to become a SAP Certified
Development Professional - SAP Hybris Commerce 6.0 Developer you have a
lot of questions like :
• How do I know I’m ready for the exam ?
• How hard are the questions ?
• How do I know what chapter I need to focus on ?
This chapter, the assessment test or pretest is designed as a mental dipstick to
know how likely you would be to successfully pass P_HYCD_60 if you were
trying today. So let’s get started, try to answer all the questions in real
conditions.

Questions

Pretest - Question 1
When you initialize SAP Hybris from ant, what actions are executed ?
1. Aborts all running cronjobs
2. Delete and recreate the database
3. Delete all known tables
4. Import all project data

Solution

Pretest - Question 2
Changing SAP Hybris configuration from the project.properties file of your
platform project is considered bad because ?
1. This doesn’t follow SAP Hybris licence
2. It makes future updates harder
3. The file is already too big
4. This file is ignored after you create a new config folder from it

Solution

Pretest - Question 3
Is this a valid Flexible Search Query ?
1 SELECT {p.pk} FROM {Principal} AS p WHERE {p.uid} = 'admin'

1. No, Principal is an abstract type


2. No, SQL aliases definition needs to be inside the brackets
3. NO, for another reason
4. Yes, this is a valid Flexible Search Query.

Solution

Pretest - Question 4
According to the following extensioninfo.xml what statements are true ?
1 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2 <extensioninfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3 xsi:noNamespaceSchemaLocation="extensioninfo.xsd">
4
5 <extension abstractclassprefix="Generated" classprefix="
HybhubStorefront"
6 name="hybhubstorefront">
7
8 <requires-extension name="assistedservicestorefront"/>
9 <requires-extension name="smarteditaddon"/>
10 <requires-extension name="captchaaddon"/>
11 <requires-extension name="acceleratorstorefrontcommons"/>
12 <requires-extension name="hybhubfacades"/>
13
14 <webmodule jspcompile="false" webroot="/hybhubstorefront"/>
15
16 <meta key="extgen-template-extension" value="true"/>
17
18 </extension>
19
20 </extensioninfo>

1. This extension could define new item types from its


hybhubstorefront-items.xml like all other extensions
2. This extension can used as a template to create a new extension
3. This extension can define HMC configuration and localization
4. This extension requires a web directory

Solution

Pretest - Question 5
Which off the following Interfaces are valid SAP Hybris interceptors ?
1. de.hybris.platform.servicelayer.interceptor.ValidateInterceptor
2. de.hybris.platform.servicelayer.interceptor.PrepareInterceptor
3. de.hybris.platform.servicelayer.interceptor.CheckInterceptor
4. de.hybris.platform.servicelayer.interceptor.InitAllInterceptor
5. de.hybris.platform.servicelayer.interceptor.RemoveInterceptor
6. de.hybris.platform.servicelayer.interceptor.DeleteInterceptor

Solution

Pretest - Question 6
What is the recommended way to create a new extension within SAP Hybris V6
?
1. Use the installer script with the extgen recipe
2. Extensions are automatically created by the build framework based on
your dependencies
3. Use the build framework with the extgen ant target to create a new
extension from a template
4. Use the build framework with the extgen maven goal to create a new
extension from a template

Solution

Pretest - Question 7
What bean would I get when I execute spring.getBean(“alias”)* for the following
spring configuration?*
1 <alias name="bean1" alias="alias"/>
2 <bean name="bean1" class="spring.exos.MyBean" />
3
4 <alias name="bean2" alias="alias"/>
5 <bean name="bean2" class="spring.exos.MyBean" />

1. bean1
2. bean2
3. alias
4. The configuration is wrong

Solution

Pretest - Question 8
Using a standard SAP Hybris configuration, is this a valid item type definition ?
1 <itemtype code="MyItem" abstract="false" extends="GenericItem">
2 </itemtype>

1. No, this item needs a deployment table


2. No, this item needs at least one attribute
3. No, only abstract items can extends GenericItem
4. No, GenericItem is a not a valid type
5. Yes, this is a valid item type definition
Solution

Pretest - Question 9
All CMS item types extend ?
1. GenericItem
2. CMS Item
3. CMSItem or CMSRelation
4. CatalogAware

Solution

Pretest - Question 10
Next Generation Cockpit dynamic forms can be used to ?
1. Automatically generate forms for new item types
2. Automatically open the next tab when required data have been entered
3. Automatically disable a field when data are entered
4. Automatically create an event when data are validated

Solution

Solutions

Pretest - Solution 1
1,4 are correct.
2. The database is never deleted by SAP Hybris even if the configured
database user had ti right to do so.
3. SAP Hybris will delete only tables he knows from its type definition.

Question
Pretest - Solution 2
2 is correct.
Keeping your configuration isolated from SAP Hybris out of the box
configuration is recommenced.

Question

Pretest - Solution 3
2 is correct.
Aliases need to be defined within the brackets to be attached to attributes
otherwise the resolver doesn’t know about it.
You can search for abstract item types within a Flexible Search Query.

Question

Pretest - Solution 4
2,4 are correct.
To be able to define new item types an extension needs to have a core module
defined. To be able to add HMC configuration an extension needs to have an
HMC module defined.

Question

Pretest - Solution 5
1,2,5 are correct.
The available interceptors are :
• PrepareInterceptor
• LoadInterceptor
• RemoveInterceptor
• ValidateInterceptor
• InitDefaultsInterceptor
Question

Pretest - Solution 6
3 is correct.
Installer script and the build framework don’t create any extensions. SAP
Hybris V6 is using ant to generate new extensions, maven can be used to
configure libraries dependencies.

Question

Pretest - Solution 7
2 is correct.
The last configured alias will be used.

Question

Pretest - Solution 8
1 is correct.
An item type definition can have no attribute and extends by default
GenericItem, but if it extends GenericItem it musts define a deployment table
for performance reasons. To ignore this set build.development.mode=false (not
recommended).

Question

Pretest - Solution 9
1,3 are correct.
All item types extend GenericItem type. All CMS item types extend either
CMSItem or CMSRelation.
Question

Pretest - Solution 10
2,3 are correct.
Dynamic forms are used to add logic within a wizard or editor area.

Question
Chapter 2

WCMS

The SAP Hybris Commerce 6.0 Developer expects you to know the Web
Content Management System (WCMS) cockpit, in this chapter readers
will learn the different CMS component hierarchy and items, learn how to
create new CMS component, explore the store and website data model, will
learn how to create a manage warehouse and point of sales, finally you will
learn how to create restriction using the BTG extension.

CMS Items hierarchy


Every CMS components inherits from the ‘CMSItem’ type, this type declare 3
attributes :
• catalogVersion
• name
• uid
Each CMS components can have multiple versions, default is a Staged and an
Online version. Hence all items within the CMS hierarchy are catalog version
aware. It gives you the ability to manage any sort of contents (Medias, Pages,
Slots, Nodes…) within one catalog version and then synchronize your content
once it’s ready to go live.
CMSItem and CMSRelation are managed inside a content catalog,
this catalog is only a subtype of the Hybris Catalog and add no extra
functionnalities
Simplified view of the CMS Items hierarchy:

16
CMSItem CMSRelation

CMSItem types

CMSItem type and CMSRelation type unicity is guaranty with a key made of
catalogVersion and UID.
1 <itemtype code="CMSItem" extends="GenericItem" ...>
2 <attributes>
3 <attribute ... qualifier="catalogVersion">
4 <modifiers ... unique="true"/>
5 </attribute>
6 <attribute ... qualifier="name">
7 </attribute>
8 <attribute ... qualifier="uid">
9 <modifiers ... unique="true" .../>
10 </attribute>
11 </attributes>
12 </itemtype>
13 <itemtype code="CMSRelation" extends="GenericItem" ...>
14 <attributes>
15 <attribute ... qualifier="catalogVersion">
16 <modifiers ... unique="true"/>
17 </attribute>
18 <attribute ... qualifier="uid">
19 <modifiers ... unique="true"/>
20 </attribute>
21 </attributes>
22 </itemtype>

When do we use CMSItem type and when do we use CMSRelation ?


• CMSItem when you create a new CMS item, like a new component or a
new type of pages.
• CMSRelation when you create a new type which is not a CMS component
but still need to be catalog version aware

CMS Components
A CMS component is a the base type of each component found on a page, a
component can be as simple as a text paragraph or something more complex
like a product rotating component. Each CMS components are made of three
things :
• an item that extends AbstractCMSComponent or one of its subtypes
• a Spring MVC controller that extends AbstractCMSComponentController
• a JSP (or other front end technology) to render the component
To change how customized item types are rendered within the
WMCS cockpit, you need to create editorArea_myType.xml,
contentEditor_myType.xml and wizardConfig_myType.xml

Example how to create a cms component

In this example we will create a CMS component to display a reminder for


a order time limit that must be complied if you want the item delivered the
following day :
1 <typegroup name="hybhubCms">
2 <itemtype code="OrderDeliveryTimeLimit" extends="
SimpleCMSComponent" autocreate="true" generate="true">
3 <description>Simple CMS component that display a reminder of
when is the limit time to order for next day delivery</
description>
4 <attributes>
5 <attribute qualifier="message" type="localized:java.lang.
String">
6 <persistence type="property" />
7 </attribute>
8 </attributes>
9 </itemtype>
10 </typegroup>

Now we need to create our controller :


1 package com.hybhub.storefront.controllers.cms;
2

3 import de.hybris.platform.servicelayer.time.TimeService;
4

5 import java.text.MessageFormat;
6 import java.util.Calendar;
7 import java.util.Date;
8

9 import javax.annotation.Resource;
10 import javax.servlet.http.HttpServletRequest;
11

12 import org.springframework.stereotype.Controller;
13 import org.springframework.ui.Model;
14 import org.springframework.web.bind.annotation.RequestMapping;
15

16 import com.hybhub.core.model.OrderDeliveryTimeLimitComponentModel;
17 import com.hybhub.storefront.controllers.ControllerConstants;
18

19

20 @Controller("OrderDeliveryTimeLimitComponentController")
21 @RequestMapping(value = ControllerConstants.Actions.Cms.
OrderDeliveryTimeLimitComponent)
22 public class OrderDeliveryTimeLimitComponentController
23 extends AbstractAcceleratorCMSComponentController
24 <OrderDeliveryTimeLimitComponentModel>
25 {
26

27 @Resource
28 private TimeService timeService;
29

30 private static final int MAX_HOUR_FOR_NEXT_DAY_DELIVERY = 16;


31

32 private static final Date DATE_LIMIT;


33

34 static
35 {
36 DATE_LIMIT = new Calendar.Builder().set(Calendar.HOUR_OF_DAY,
MAX_HOUR_FOR_NEXT_DAY_DELIVERY).set(Calendar.SECOND, 0)
37 .build().getTime();
38 }
39

40 @Override
41 protected void fillModel(final HttpServletRequest request, final
Model model,
42 final OrderDeliveryTimeLimitComponentModel component)
43 {
44 final Calendar cal = new Calendar.Builder().setInstant(
timeService.getCurrentTime()).build();
45 model.addAttribute("nextDayDelivery", (Boolean.valueOf(cal.
get(Calendar.HOUR_OF_DAY) <
MAX_HOUR_FOR_NEXT_DAY_DELIVERY)));
46 model.addAttribute("nextDayDeliveryMessage", MessageFormat.
format(component.getMessage(), DATE_LIMIT));
47 }
48 }

Creating a controller is not mandatory. If you don’t the


DefaultCMSComponentController will be used, it loads all
attributes from the item type and load them into your model
We need to create a JSP to display our cms component, create a new file
hybhubstorefront/web/webroot/WEB-INF/views/responsive/cms/
orderdeliverytimelimitcomponent.jsp:
1 <%@ page trimDirectiveWhitespaces="true"%>
2
3 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
4 <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
5 <div class="ui-front">
6 <p>
7 <c:if test="${nextDayDelivery}">
8 ${nextDayDeliveryMessage}
9 </c:if>
10 <c:if test="${not nextDayDelivery}">
11 <fmt:message key="next.day.delivery.tooLate"/>
12 </c:if>
13 </div>

Add this into your localization :


1 next.day.delivery.tooLate = Too late for next
delivery

Run ant all, start your server and update your system, then run this (example
based on the electronic store front) :
1 $contentCatalog=electronicsContentCatalog
2 $contentCatalogName=Electronics Content Catalog
3 $contentCV=catalogVersion(CatalogVersion.catalog(Catalog.id[default=
$contentCatalog]),CatalogVersion.version[default=Online])[default
=$contentCatalog:Online]
4
5 INSERT_UPDATE OrderDeliveryTimeLimitComponent;$contentCV[unique=true
];uid[unique=true];name;message[lang=en];&componentRef;
6 ;;orderDeliveryTimeLimitComponent;order Delivery Time Limit Component
;"Order before {0} to receive your order tomorrow.";
orderDeliveryTimeLimitComponent;
7
8 INSERT_UPDATE ContentSlot;$contentCV[unique=true];uid[unique=true];
name;active;cmsComponents(&componentRef)
9 ;;Section1Slot-Homepage;Section1 Slot for Homepage;true;
orderDeliveryTimeLimitComponent

You should now see your new CMS component under your home page.

Personalization
The BTG extension (Behavioral Targeting Group) provides the AP module
(Advanced Personalization), with this module activated you can customize per
customer the CMS items to display or to add. SAP Hybris customer
segmentation groups your customers into multiple subset and activate actions.

Segmentation rules

Out of the box you have access to pre-configured segmentation rules :


• Cart rules
• cart is empty
• total sum of cart
• categories of products in cart
• products in cart
• size of the cart
• quantity of one product in cart
• Order rules
• categories of product in last orders
• each last orders total sum
• total order value
• products in last orders
• number of orders in a date range
• last order date
• Customer rules
• belongs to a group
• gender
• country
• postal code
• Website rules
• has viewed products
• has viewed categories
• has viewed content page
• referral URL match
• URL contains parameter

Segmentation actions

• assign user to group


• cms restriction

Create a CMS restriction

Example from the electronics store default segmentation :


1 ##################################################################
2 # Configuration 1: Regular Customer Segment
3 ##################################################################
4 INSERT_UPDATE BTGSegment;uid[unique=true];name;sites(uid);active[
default=true];scope(code)[default=ONLINE];$contentCatalogVersion
5 ;electronicsRegularCustomerSegment;Regular Customer Segment;
electronics
6
7 INSERT_UPDATE BTGRule;uid[unique=true];code;segment(uid,
$contentCatalogVersion);ruleType(code);$contentCatalogVersion
8 ;electronicsRegularCustomerRule;Regular Customer Rule;
electronicsRegularCustomerSegment;ORDER
9
10 INSERT_UPDATE BTGOperator;uid[unique=true];code;
$contentCatalogVersion
11 ;electronicsGreaterOperator;numGreaterThanOrEqual
12
13 INSERT_UPDATE BTGNumberOfOrdersRelativeDateOperand;uid[unique=true];
value;unit(code);$contentCatalogVersion
14 ;electronicsNumberOfOrdersOperand;6;MONTH
15
16 INSERT_UPDATE BTGIntegerLiteralOperand;uid[unique=true];literal;
$contentCatalogVersion
17 ;electronicsOrdersIntegerOperand;4
18
19 INSERT_UPDATE BTGExpression;uid[unique=true];leftOperand(uid,
$contentCatalogVersion);rightOperand(uid, $contentCatalogVersion)
;operator(uid, $contentCatalogVersion);rule(uid,
$contentCatalogVersion);$contentCatalogVersion
20 ;electronicsRegularCustomerExpression;
electronicsNumberOfOrdersOperand;electronicsOrdersIntegerOperand;
electronicsGreaterOperator;electronicsRegularCustomerRule
21
22 INSERT_UPDATE BTGAssignToGroupDefinition;uid[unique=true];code;target
;userGroups(uid);segment(uid, $contentCatalogVersion);
$contentCatalogVersion
23 ;electronicsBtgAssignToRegularGroup;Add to Regular Segment;
assignToGroup;regulargroup;electronicsRegularCustomerSegment

A customer segment can be evaluated in 2 different modes :


1. optimized processing, evaluation of the segment stops after the first rule
that could not be fulfilled
2. full processing, all segment rules are evaluated, whether they have been
fulfilled or not Full processing has an impact on performances !

WCMS cockpit
SAP Hybris end users can use the WCMS (Web Content Management System)
cockpit (based on the legacy cockpit framework, hopefully future versions will
include a revamped WCMS cockpit using the next generation cockpit
framework). It provides an easy way for end users to manage web contents
such as :
• manage pages
• manage cms components
• synchronize components and pages between different catalogs
• manage navigation nodes
• manage advanced personalization (if BTG cockpit is activated)

Warehouse & point of service

Warehouse

Warehouses are part of the order splitting package, each warehouse is linked to
one or more base store, under each warehouse you find stock levels.
Warehouses are used by the stock service and splitting strategies.

Point of services

A point of service can be of different types :


• store
• warehouse
• point of service
Each point of service is linked to one or more warehouses, the store point of
services are used by the store locator feature.
Chapter 3

Backoffice & Cockpits


modifications

The backoffice (or next generation cockpit) replaces the cockpit framework, in
future versions all existing cockpits (hmc, cs, wcms…) will be replaced by a new
one using the backoffice cockpit. The key feature of the backoffice framework
is the concept of widget, each widget is an independent component that can be
reused and connected to other widgets. An application orchestrator allows you
to build a new backoffice from the backoffice itself.

Create a new Backoffice application


To create a new backoffice run the ant target ant extgen and select the template
ybackoffice, follow the instructions and select a name, a package and ask the
template to create a sample widget.
A backoffice extension has :
• backoffice configuration inside its extensioninfo.xml
1 <meta key="backoffice-module" value="true" />

• backoffice folder, inside this folder you will find


• classes
• src
• testsrc
• resources
• cng, customize backoffice css
• widgets, widget components configuration
– , each widget has a folder with its own name

25
– images, folder for widget’s images
– labels, folder for widget’s localization
– definition.xml, your widget definition
– .css
– .zul
– cockpit-config.xml, default configuration for your widget
– editors or actions, folder for new editors and actions (editors to edit
item types that are not supported by the backoffice and actions to
perfom business)
– images
– labels, your widget localization
– definition.xml, your widget definition
– .css
The backoffice has one shared configuration file where users have different
business roles, they would see different perspectives and have different rights.
The admin can see all perspectives and reorganize them from the orchestrator.
To configure a new perspective you need to edit file
hybhubbackoffice/resources/hybhubbackoffice-backoffice-config.xml (where
hybhubbackoffice is the name of my custom extension built from the ybackoffice
template).
During backoffice development activate the following property :
backoffice.cockpitng.hotDeployment.enabled=true to be able to
reload the backoffice application without restarting your server.
Run ant build and click on redeploy from the backoffice admin
perspective.
To create a new backoffice perspective you need to :
1. create a new BackofficeRole group
2. create a new UserGroup member of the new BackofficeRole group and the
employeegroup group
3. create users member of the new group
4. update your backoffice configuration, add a new perspective by configuring
the principal attribute of contexts to your new backoffice role.

Create & connect a new widget


To speed up widgets development, deactivate all cache :
1 backoffice.cockpitng.additionalResourceLoader.enabled=true
2 backoffice.cockpitng.uifactory.cache.enabled=false
3 backoffice.cockpitng.widgetclassloader.resourcecache.enabled=false
4 backoffice.cockpitng.resourceloader.resourcecache.enabled=false

Create a widget to filter reviews by status :


1 <widget-definition xmlns:xsi="http://www.w3.org/2001/XMLSchema-
instance"
2 xsi:noNamespaceSchemaLocation="http://www.hybris.com/schema/
cockpitng/widget-definition.xsd"
3 id="com.hybhub.backoffice.widgets.
customerreviewselectorbackofficewidget">
4 <name>Customer Review Selector</name>
5 <description>Customer Review Selector - Select pending reviews,
denied reviews or approved reviews </description>
6 <defaultTitle>Customer Review Selector</defaultTitle>
7 <author>Hybhub</author>
8 <version>1.0</version>
9 <view src="customerreviewselectorwidget.zul" />
10 <keywords>
11 <keyword>customerreviewselector</keyword>
12 </keywords>
13 <controller class="com.hybhub.backoffice.widgets.
CustomerreviewbackofficeController" />
14 <settings>
15 <setting key="type" type="ENUM(Pending,Approved,Rejected)"/>
16 <setting key="name" type="String"/>
17 </settings>
18 <sockets>
19 <output type="com.hybris.cockpitng.search.data.pageable.
Pageable" id="reviews"/>
20 </sockets>
21 </widget-definition>

Create a controller :
1 package com.hybhub.backoffice.widgets;
2

3 import de.hybris.platform.customerreview.enums.
CustomerReviewApprovalType;
4 import de.hybris.platform.customerreview.model.CustomerReviewModel;
5

6 import org.zkoss.zk.ui.Component;
7 import org.zkoss.zk.ui.event.Events;
8 import org.zkoss.zk.ui.select.annotation.WireVariable;
9 import org.zkoss.zul.Button;
10

11 import com.hybhub.services.CustomerReviewSearchService;
12 import com.hybris.cockpitng.annotations.ViewEvent;
13 import com.hybris.cockpitng.search.data.pageable.PageableList;
14 import com.hybris.cockpitng.util.DefaultWidgetController;
15
16

17 public class CustomerreviewbackofficeController extends


DefaultWidgetController
18 {
19 private Button reviews;
20

21 @WireVariable
22 private CustomerReviewSearchService customerReviewSearchService;
23

24 @Override
25 public void initialize(final Component comp)
26 {
27 super.initialize(comp);
28 reviews.setLabel(this.getWidgetSettings().getString("name"));
29 }
30

31 @ViewEvent(componentID = "reviews", eventName = Events.ON_CLICK)


32 public void sendReviews()
33 {
34 final CustomerReviewApprovalType approvalType =
CustomerReviewApprovalType
35 .valueOf(this.getWidgetSettings().getString("type"));
36

37 sendOutput("reviews", new PageableList<CustomerReviewModel>(


customerReviewSearchService.getAllCustomerReviews(
approvalType),
38 10, CustomerReviewModel._TYPECODE));
39

40 }
41

42 }

And a view :
1 <?xml version="1.0" encoding="UTF-8"?>
2
3 <widget xmlns="http://www.zkoss.org/2005/zul"
4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5 xmlns:h="http://www.w3.org/1999/xhtml"
6 xmlns:w="http://www.zkoss.org/2005/zk/client"
7 xmlns:zk="http://www.zkoss.org/2005/zk"
8 xsi:schemaLocation="http://www.zkoss.org/2005/zul http://www.
hybris.com/schema/cockpitng/zul/zul.xsd"
9 height="100%">
10
11 <div height="100%" style="background: #ccc;">
12 <div>
13 <button id="reviews" label="Pending Reviews"/>
14 </div>
15 <widgetchildren slotID="additionalArea" id="additionalArea"
type="tab" width="100%" height="100%"/>
16 </div>
17 </widget>

Legacy Cockpit modification


The legacy cockpit framework is slowly being removed by the next generation
cockpit framework, but it won’t be done before mid 2018, for more information
have a look at the deprecation status page on SAP Hybris wiki. Therefore it’s
really important to know how to work with the cockpit framework.
Within a cockpit you have different key elements :
• Navigation area, where can find tree views, links, history…
• Browser area, where you see a list or grid of elements.
• Editor area, displays an item and provides the option to edit it.
To import cockpit configuration you have two choices :
• automatically if you respect the out of the box naming convention
• manually (not recommended)
To automatically import cockpit configuration the convention requires :
• a folder resources/-config
• the main folder cannot be empty and must contain at least :
• a XML configuration that affects all users and user groups
• a folder with XML configuration inside. The folder name needs to be user
id or a group id (validated during the import). It can contain only XML
files and no subfolders, inside this folder you have configuration files :
• they must match this pattern contextID _ ObjectTemplateCode.xml
• available context IDs are defined within the bean ctxID2FactoryMappings
• ObjectTemplateCode are item types and are validated by the type service
Chapter 4

Commerce and Accelerator

Create New Addon


Addons are used to extend the functionnalities of SAP Hybris platform without
changing its source code, they are standard extensions and are loaded during
the build phase, therefore they can be used to customize item types using their
own items.xml file or beans using their own beans.xml file. From an addon you
could:
• add front end files (JSP, HTML, CSS and Javascript)
• Generate or customize Facade transfert objects (DTO)
• Generate or customize the data model
• Declare new Spring Services or Facades or customize existing
• Declare new Controllers or customize existing
• Declare new Converters or populators or customize existing
An extension is an Addon when it requires the addonsupport extension and when
the targeted extension requires the given addon.
First you need to generate a new extension based on the yaddon template,
I called my extension hybhubaddon and choose com.hybhub.hybhubaddon as a
package name :
1 Buildfile: /Users/j.doe/Workspace/workspace-perso/hybris/hybris
-6.0.0/hybris/bin/platform/build.xml
2 [echo] /Workspace/hybris/hybris-6.0.0/hybris/bin/platform/tomcat
/bin
3 .....
4 [echo] -----
5 [echo] hybris Platform Environment
6 [echo] -----
7 [echo] OS family: unix

30
8 [echo] Java platform: Java(TM) SE Runtime
Environment, 1.8.0_60-b27
9 [echo] Java compiler: org.eclipse.jdt.core.
JDTCompilerAdapter
10 [echo] Build target: 1.8
11 [echo] Compilation mode: strict
12 [echo] hybris Platform directory: /Workspace/hybris/hybris
-6.0.0/hybris/bin/platform
13 [echo] hybris Platform version: 6.0.0.0-SNAPSHOT
14 [echo] Ant version: Apache Ant(TM) version 1.9.1
compiled on May 15 2013
15 [echo] Ant memory settings: -Xmx512m -Dfile.encoding=UTF-8
16 [echo] -----
17 .....
18 [echo] -----
19 [echo]
20
21 extgen:
22 [input]
23 [input] Please choose a template for generation.
24 [input] Press [Enter] to use the default value (ywebservices,
ysmarteditmodule, yhacext, [yempty], ycmssmartedit,
yatddtests, yscala, ygroovy, ycockpit, yoccaddon, yaddon,
ycommercewebservices, ycommercewebservicestest,
ycommercewebserviceshmc, ychinaacceleratorstorefront,
yacceleratorordermanagement, yacceleratorstorefront,
yacceleratorfractusfulfilmentprocess,
yacceleratorfulfilmentprocess, ybackoffice)
25 yaddon
26 [input]
27 [input] Please choose the name of your extension. It has to start
with a letter followed by letters and/or numbers.
28 [input] Press [Enter] to use the default value [training]
29 hybhubaddon
30 [input]
31 [input] Please choose the package name of your extension. It has
to fulfill java package name convention.
32 [input] Press [Enter] to use the default value [org.training]
33 com.hybhub.hybhubaddon
34 [echo] Using extension template source: /Workspace/hybris/hybris
-6.0.0/hybris/bin/ext-template/yaddon
35 [mkdir] Created dir: /Workspace/hybris/hybris-6.0.0/hybris/temp/
hybris/extgen
36 [echo] Copying template files from /Workspace/hybris/hybris
-6.0.0/hybris/bin/ext-template/yaddon to /Workspace/hybris/
hybris-6.0.0/hybris/temp/hybris/extgen
37 [copy] Copying 156 files to /Workspace/hybris/hybris-6.0.0/
hybris/temp/hybris/extgen
38 [copy] Copying 156 files to /Workspace/hybris/hybris-6.0.0/
hybris/temp/hybris/extgen_final
39 [mkdir] Created dir: /Workspace/hybris/hybris-6.0.0/hybris/bin/
custom/hybhubaddon/lib
40 [copy] Copying 143 files to /Workspace/hybris/hybris-6.0.0/
hybris/bin/custom/hybhubaddon
41 [echo]
42 [echo]
43 [echo] Next steps:
44 [echo]
45 [echo] 1) Add your extension to your /Workspace/hybris/hybris
-6.0.0/hybris/config/localextensions.xml
46 [echo]
47 [echo] <extension dir="/Workspace/hybris/hybris-6.0.0/
hybris/bin/custom/hybhubaddon"/>
48 [echo]
49 [echo] 2) Please remove all template extensions (again) before
you proceed.
50 [echo]
51 [echo] 3) Make sure the applicationserver is stopped before you
build the extension the first time.
52 [echo]
53 [echo] 4) Perform 'ant' in your hybris/platform directory.
54 [echo]
55 [echo] 5) Restart the applicationserver
56 [echo]
57 [echo]
58
59 BUILD SUCCESSFUL
60 Total time: 29 seconds

After adding your addon to your eclipse environment and to your


localextensions.xml file you’ll notice that it looks like any other extension
except for the acceleratoraddon folder, this folder structure is a copy of the
usual structure of a front end extension.
Next step is to install your addon into the designated store front extension, for
this we use ant:
1 ant addoninstall -Daddonnames="AddOnName1,AddOnName2" -
DaddonStorefront.yacceleratorstorefront="B2CStorefront1,
B2CStorefront2" -DaddonStorefront.yb2bacceleratorstorefront="
B2BStorefront1,B2BStorefront2"

In my case my addon’s name is hybhubaddon and the store front extension I’m
using is yacceleratorstorefront so I need to execute :
1 ant addoninstall -Daddonnames="hybhubaddon" -DaddonStorefront.
yacceleratorstorefront="yacceleratorstorefront"
2 .....
3 addoninstall:
4 [echo] Storefront templates found in command line :
yacceleratorstorefront,
5 [delete] Deleting: /Workspace/hybris/hybris-6.0.0/hybris/bin/
platform/null2070331373
6 [echo] AddOn name list: hybhubaddon
7 [echo] ------------------Instaling addon : hybhubaddon
---------------
8 [echo] Generate project.properties file from template /Workspace
/hybris/hybris-6.0.0/hybris/bin/custom/hybhubaddon/project.
properties.template
9 [copy] Copying 1 file to /Workspace/hybris/hybris-6.0.0/hybris/
bin/custom/hybhubaddon
10 [echo] Add additionalWebSpringConfigs line for
storefrontTemplate 'yacceleratorstorefront' and storefronts
'yacceleratorstorefront'
11 [propertyfile] Updating property file: /Workspace/hybris/hybris
-6.0.0/hybris/bin/custom/hybhubaddon/project.properties
12 [echo] Adding addon 'hybhubaddon' to extensioninfo.xml for '
yacceleratorstorefront'
13 [echo] Adding addon 'hybhubaddon' to addons.less for '
yacceleratorstorefront'
14
15 BUILD SUCCESSFUL
16 Total time: 2 seconds

The addoninstall target does a couple a things :


• Generate a new project.properties file from the project.properties.template
inside your addon.
• Configure the hybhubaddon web spring configuration
hybhubaddon-web-spring.xml into
yacceleratorstorefront.additionalWebSpringConfigs
• Add hybhubaddon into extensioninfo.xml for yacceleratorstorefront
• Add hybhubaddon to addons.less for yacceleratorstorefront
If you need to uninstall an Addon you could use :
1 ant addonuninstall -Daddonnames="hybhubaddon" -DaddonStorefront.
yacceleratorstorefront="yacceleratorstorefront"
2 .....
3 addonuninstall:
4 [echo] Storefront templates found in command line :
yacceleratorstorefront,
5 [delete] Deleting: /Workspace/hybris/hybris-6.0.0/hybris/bin/
platform/null583120343
6 [echo] AddOn name list: hybhubaddon
7 [echo] ------------------Uninstaling addon : hybhubaddon
---------------
8 [echo] Removing addon 'hybhubaddon' from extensioninfo.xml for '
yacceleratorstorefront'
9 [echo] Removing addon 'hybhubaddon' from addons.less for '
yacceleratorstorefront'
10
11 BUILD SUCCESSFUL
12 Total time: 2 seconds

Your new Addon extension has few files under its acceleratoraddon folder :

acceleratoraddon/web/webroot/_ui/responsive/common/css/hybhubaddon.css
• acceleratoraddon/web/webroot/WEB-INF/_ui-
src/responsive/less/hybhubaddon.less
Create a new JSP file under the folder acceleratoraddon/web/webroot/WEB-
INF/views/responsive/pages/layout, hybhubAddonLayout.jsp :
1 <%@ page trimDirectiveWhitespaces="true"%>
2 <%@ taglib prefix="template" tagdir="/WEB-INF/tags/responsive/
template"%>
3
4 <template:page pageTitle="${pageTitle}">
5 <h1>From Hybhub Addon</h1>
6 </template:page>

Create a new controller under the package


com.hybhub.hybhubaddon.controllers.pages (you may need to add the folder
acceleratoraddon/web/src under your java build path source) :
1 package com.hybhub.hybhubaddon.controllers.pages;
2

3 import de.hybris.platform.addonsupport.controllers.page.
AbstractAddOnPageController;
4 import de.hybris.platform.cms2.exceptions.CMSItemNotFoundException;
5 import de.hybris.platform.cms2.model.pages.ContentPageModel;
6

7 import org.springframework.stereotype.Controller;
8 import org.springframework.ui.Model;
9 import org.springframework.web.bind.annotation.RequestMapping;
10 import org.springframework.web.bind.annotation.RequestMethod;
11

12
13 @Controller
14 @RequestMapping(value = "/hybhub")
15 public class HybHubAddonPageController extends
AbstractAddOnPageController
16 {
17

18 @RequestMapping(method = RequestMethod.GET)
19 public String hybhub(final Model model) throws
CMSItemNotFoundException
20 {
21 final ContentPageModel page = getContentPageForLabelOrId(null
);
22 storeCmsPageInModel(model, page);
23 setUpMetaDataForContentPage(model, page);
24

25 return "addon:/hybhubaddon/pages/layout/hybhubAddonLayout";
26 }
27 }

Update the file hybhubaddon/resources/hybhubaddon/web/spring/hybhubaddon-


web-spring.xml to add a context component-scan element :
1 .....
2 <context:annotation-config/>
3 <context:component-scan base-package="com.hybhub.hybhubaddon.
controllers"/>
4 .....

Build your platform and start your server, now when you access
https://localhost:
9002/yacceleratorstorefront/electronics/en/hybhub?site=electronics you
should see :
What have we done ? We have customized the store front extension without
changing it, so we could easily deploy this on any other project.

OCC Webservices
The Omni Commerce Connect module is a set of API that expose services and
data from Hybris. All webservices are Restful web services and support both
JSON and XML format.Web services are build with the Spring MVC framework,
using controllers, facades and converters.
The OCC module contains the following extensions:
• commercewebservicescommons
• ycommercewebservices
– Authentication uses the OAuth2 framework.
– Object can be cached using the Ehcache, cache is configured for each
controller and method with the @Cacheable annotation
• ycommercewebserviceshmc
• ycommercewebservicestest
Remember that all extensions starting with a y are templates and
are made to be reused as templates, so to add new webservices or
to change existing web services you will need to generate a new
commerce web service extensions from the
ycommercewebservices template.
Currently 2 versions of the web services coexists:
• V1 (/v1/*) which is the old version released with Hybris V5.1. The key
features of version 1 are:
– Stateful
– Response format (XML or JSON)
• V2 (/v2/*) which is the current version of the web services released with
Hybris 5.4. The key features of version 2 are :
– stateless
– Restful
– Data creation
Type of requests:
• GET a request to get data
• POST a request to create data
• PUT a request to update data
• HEAD a request to get information about the data (number of elements
for example)
Remember that OCC doesn’t use normal users, it has its own data
type to manage credentials, have a look at OAuthClientDetails
1 <itemtype code="OAuthClientDetails" generate="true" autocreate="true"
>
2 <deployment table="OAuthClientDetails" typecode="6500" />
3
4 <attributes>
5 <attribute qualifier="clientId" type="java.lang.String">
6 <description>Client Id</description>
7 <modifiers unique="true" optional="false" initial="true"
write="false" />
8 <persistence type="property" />
9 </attribute>
10
11 <attribute qualifier="resourceIds" type="StringSet">
12 <description>Set of Resource Id's</description>
13 <persistence type="property" />
14 </attribute>
15
16 <attribute qualifier="clientSecret" type="java.lang.String">
17 <description>Client Secret</description>
18 <persistence type="property" />
19 </attribute>
20
21 <attribute qualifier="scope" type="StringSet">
22 <description>Set of client scopes</description>
23 <persistence type="property" />
24 </attribute>
25
26 <attribute qualifier="authorizedGrantTypes" type="StringSet"
>
27 <description>Set of grant types for client</description>
28 <persistence type="property" />
29 </attribute>
30
31 <attribute qualifier="registeredRedirectUri" type="StringSet
">
32 <description>Set of redirect Uri for client</description>
33 <persistence type="property" />
34 </attribute>
35
36 <attribute qualifier="authorities" type="StringSet">
37 <description>Set of authorities granted to client</
description>
38 <persistence type="property" />
39 </attribute>
40
41 <attribute qualifier="accessTokenValiditySeconds" type="java
.lang.Integer">
42 <description>Set of authorities granted to client</
description>
43 <persistence type="property" />
44 </attribute>
45
46 <attribute qualifier="refreshTokenValiditySeconds" type="
java.lang.Integer">
47 <description>Set of authorities granted to client</
description>
48 <persistence type="property" />
49 </attribute>
50
51 <attribute qualifier="autoApprove" type="StringSet">
52 <description>Set of auto approve scopes of client</
description>
53 <persistence type="property" />
54 </attribute>
55 </attributes>
56
57 <indexes>
58 <index name="clientIdIdx" unique="true">
59 <key attribute="clientId" />
60 </index>
61 </indexes>
62 </itemtype>
Install OCC

To activate and use the Omni Channel Connect module you need to have these
extension activated :
• ycommercewebservices
• ycommercewebserviceshmc
• ycommercewebservicestest
• commercewebservicescommons
• webservicescommonsbackoffice
• cmswebservices
If you have created your own web services extensions from the y
templates, then delete the reference to the web services templates
from your localextensions.xml file.
Once you have updated your Hybris installation with the required extensions
you would be able to manage the OAuthClientDetails and see the current
OAuthAccessToken from the backoffice.

OAUTH

Hybris web services authentification mechanism is based on OAuth, each calls


to the OCC web services have to go through a complex authentification
mechanism, first the user will be authenticated (verifying credentials) then the
user is authorized (decide whether or not the user can perform a given action).
Authorization happens within the HTTP layer and the Service layer, each of
them applying its own set of verification.

OCC user roles


Authentification
type Role
Anonymous A non-authenticated principal is assigned a built-in
ANONYMOUS role by default.
Client Every client application that was authenticated using
an OAuth2 token in the client credentials flow is
assigned a specific role depending on the client
definition. When defining the clients remember to
assign either the ROLE_CLIENT or
ROLE_TRUSTED_CLIENT to them, because these
roles allow client access to the ycommercewebservices
extension
Customers Users who were authenticated using the OAuth2 token
in the password flow, are assigned a list of roles that
are received from a service layer in the same way as it
works in the whole application. By default,
CUSTOMERGROUP and
CUSTOMERMANAGERGROUP roles are used.
Guest Anonymous users who provided their own e-mail
address. It can be done by calling
/customers/current/guestlogin in v1 or
/users/anonymous/carts/{guid}/email in v2. For such
users, a built-in GUEST role is assigned.

How to get a token ?

First you need to have OAuth clients configured, you can check this from the
backoffice (System -> OAuth -> OAuth Clients), if you don’t have any you
could import the one provided with the cmswebservices extension inside the
impex file sampledata-oauthclients.impex.
1 INSERT_UPDATE OAuthClientDetails;clientId[unique=true];resourceIds;
scope;authorizedGrantTypes;authorities;clientSecret;
registeredRedirectUri
2 ;client-side;hybris;basic;implicit,client_credentials;ROLE_CLIENT;
secret;http://localhost:9001/authorizationserver/
oauth2_implicit_callback;
3 ;mobile_android;hybris;basic;authorization_code,refresh_token,
password,client_credentials;ROLE_CLIENT;secret;http://localhost
:9001/authorizationserver/oauth2_callback;
4 ;trusted_client;hybris;extended;authorization_code,refresh_token,
password,client_credentials;ROLE_TRUSTED_CLIENT;secret;;

Curl
1 curl -k -X POST https://localhost:9002/authorizationserver/oauth/
token\?client_id\=trusted_client\&client_secret\=secret\&
grant_type\=client_credentials
2 {
3 "access_token" : "16582579-a158-4c31-ad3a-438c9e587dae",
4 "token_type" : "bearer",
5 "scope" : "extended",
6 "expires_in" : 41780
7 }%

-k: Allow connections to SSL sites without certs -X POST: –request


COMMAND Specify request command to use

Postman
Post Request: https://localhost:9002/authorizationserver/oauth/token?client_
id=trusted_client&client_secret=secret&grant_type=client_credentials

Create / customize webservices

When you want to add multiple webservices or customize multiple existing


web services the best solution is to generate a new extension from the
ycommercewebservices template, like what you do when you want to develop a
new store front you use the yacceleratorstorefront template to generate a new
extension from where you start your development.
The alternative is to create a new addon to extend existing API or
add new one, this could be a valid solution in some cases.
The first step is to generate a new extension from the ycommercewebservices
extension:
1 �
2 platform ant extgen
3 Buildfile: /Workspace/hybris/hybris-6.0.0/hybris/bin/platform/build.
xml
4 [echo] /Workspace/hybris/hybris-6.0.0/hybris/bin/platform/tomcat
/bin
5 [echo] /Workspace/hybris/hybris-6.0.0/hybris/bin/platform/ext/
core/web/webroot/WEB-INF/external-dependencies.xml was not
found!
6 [ysetplatformproperties] Starting platform in extgen mode...
7 ...
8 ...
9 [echo] commercesearchbackoffice->(backoffice,cms2,commercesearch
,commercefacades) 6.0.0.0-SNAPSHOT [cib] path:/Workspace/
hybris/hybris-6.0.0/hybris/bin/ext-backoffice/
commercesearchbackoffice
10 [echo] mcc->(impex,processing,cockpit) 6.0.0.0-SNAPSHOT [ciw]
path:/Workspace/hybris/hybris-6.0.0/hybris/bin/ext-cockpit/
mcc
11 [echo] -----
12 [echo]
13
14 extgen:
15 [input]
16 [input] Please choose a template for generation.
17 [input] Press [Enter] to use the default value (ywebservices,
ysmarteditmodule, yhacext, [yempty], ycmssmartedit,
yatddtests, yscala, ygroovy, ycockpit, yoccaddon, yaddon,
ycommercewebservices, ycommercewebservicestest,
ycommercewebserviceshmc, ychinaacceleratorstorefront,
yacceleratorordermanagement, yacceleratorstorefront,
yacceleratorfractusfulfilmentprocess,
yacceleratorfulfilmentprocess, ybackoffice)
18 ycommercewebservices
19 [input]
20 [input] Please choose the name of your extension. It has to start
with a letter followed by letters and/or numbers.
21 [input] Press [Enter] to use the default value [training]
22 mywebservices
23 [input]
24 [input] Please choose the package name of your extension. It has
to fulfill java package name convention.
25 [input] Press [Enter] to use the default value [org.training]
26 com.hybhub.webservices
27 [echo] Using extension template source: /Workspace/hybris/hybris
-6.0.0/hybris/bin/ext-template/ycommercewebservices
28 [mkdir] Created dir: /Workspace/hybris/hybris-6.0.0/hybris/temp/
hybris/extgen
29 [echo] Copying template files from /Workspace/hybris/hybris
-6.0.0/hybris/bin/ext-template/ycommercewebservices to /
Workspace/hybris/hybris-6.0.0/hybris/temp/hybris/extgen
30 [copy] Copying 485 files to /Workspace/hybris/hybris-6.0.0/
hybris/temp/hybris/extgen
31 [copy] Copying 485 files to /Workspace/hybris/hybris-6.0.0/
hybris/temp/hybris/extgen_final
32 [mkdir] Created dir: /Workspace/hybris/hybris-6.0.0/hybris/bin/
custom/mywebservices/lib
33 [copy] Copying 297 files to /Workspace/hybris/hybris-6.0.0/
hybris/bin/custom/mywebservices
34 [echo]
35 [echo]
36 [echo] Next steps:
37 [echo]
38 [echo] 1) Add your extension to your /Users/workspace-perso/
hybris/hybris-6.0.0/hybris/config/localextensions.xml
39 [echo]
40 [echo] <extension dir="/Workspace/hybris/hybris-6.0.0/
hybris/bin/custom/mywebservices"/>
41 [echo]
42 [echo] 2) Please remove all template extensions (again) before
you proceed.
43 [echo]
44 [echo] 3) Make sure the applicationserver is stopped before you
build the extension the first time.
45 [echo]
46 [echo] 4) Perform 'ant' in your hybris/platform directory.
47 [echo]
48 [echo] 5) Restart the applicationserver
49 [echo]
50 [echo]
51
52 BUILD SUCCESSFUL
53 Total time: 27 seconds�
54 platform

Once you have generated the new extension you need to remove the
ycommercewebservices from the localextensions.xml file and add your new
mywebservices into it.
1 <hybrisconfig xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xsi:noNamespaceSchemaLocation='../bin/platform/resources/schemas/
extensions.xsd'>
2 <extensions>
3 <path dir='${HYBRIS_BIN_DIR}' autoload='false' />
4 ...
5 <extension name="mywebservices"/>
6 ...
7 </extensions>
8 </hybrisconfig>

Run ant clean all to check that the build is not broken before you start
developing anything.
We are going to add a new web service under the version 2 structure, our web
service will simply give a list of String of all running cronjob codes, to do so we
need to create a new class CronJobsController under web/src source folder and
inside the com.hybhub.webservices.v2.controller package :
1 package com.hybhub.webservices.v2.controller;
2

3 import de.hybris.platform.servicelayer.cronjob.CronJobService;
4 import java.util.stream.Collectors;
5 import javax.annotation.Resource;
6 import org.springframework.security.access.annotation.Secured;
7 import org.springframework.stereotype.Controller;
8 import org.springframework.web.bind.annotation.RequestMapping;
9 import org.springframework.web.bind.annotation.RequestMethod;
10 import org.springframework.web.bind.annotation.ResponseBody;
11 import com.hybhub.webservices.dto.cronjob.CronJobListWsDTO;
12

13 @Controller
14 @RequestMapping(value = "/{baseSiteId}/cronjobs")
15 public class CronJobsController extends BaseController
16 {
17 @Resource
18 CronJobService cronJobService;
19

20 @Secured("ROLE_TRUSTED_CLIENT")
21 @RequestMapping(value = "/running", method = RequestMethod.GET)
22 @ResponseBody
23 public CronJobListWsDTO getRunningCronJobCode()
24 {
25 final CronJobListWsDTO cronJobList = new CronJobListWsDTO();
26 cronJobList.setCronJobsCode(
27 cronJobService.getRunningOrRestartedCronJobs().
28 parallelStream().map(c -> c.getCode()).collect(
Collectors.toList()));
29 return cronJobList;
30 }
31 }

We need to create the java bean CronJobListWsDTO using


mywebservices-beans.xml file :
1 <bean class="com.hybhub.webservices.dto.cronjob.CronJobListWsDTO">
2 <property name="cronJobsCode" type="java.util.List&lt;java.lang.
String>"/>
3 </bean>

Run ant clean all then start your server, check that you have at least one running
cronjob otherwise your list will be empt, then you can call our newly created
webservice :

Don’t forget that you first to generate a token as


ROLE_TRUSTED_CLIENT in order to call the new webservice
since we have declared it with
@Secured(“ROLE_TRUSTED_CLIENT”)
Why do we use CronJobListWsDTO and not simply a List of String ? HTTP
message converters operate only on the dedicated DTO objects. Marshallers
operate mainly on properties and, because of this, marshaling performed with
commonly uses classes such as java.util.ArrayList or java.lang.String is not
possible. The simplest solution is to wrap them using a dedicated DTO object.
How to cache a webservice ? First we need to create a new cache config for our
cronjob controller, open the file
mywebservices/web/webroot/WEB-INF/cache/ehcache.xml and add :
1 <cache name="cronjobCache"
2 maxElementsInMemory="1"
3 eternal="false"
4 overflowToDisk="true"
5 timeToLiveSeconds="30"
6 diskPersistent="false"
7 maxElementsOnDisk="100"
8 memoryStoreEvictionPolicy="LRU"/>

Then update our controller to be Cacheable, this example is really basic we only
cache the answer for one key and for 30 seconds, you can find more complex
examples in other controllers :
1 @Controller
2 @CacheControl(directive = CacheControlDirective.PUBLIC, maxAge = 30)
3 @RequestMapping(value = "/{baseSiteId}/cronjobs")
4 public class CronJobsController extends BaseController
5 ...
6 @Secured("ROLE_TRUSTED_CLIENT")
7 @RequestMapping(value = "/running", method = RequestMethod.GET)
8 @Cacheable(value = "cronjobCache", key = "T(de.hybris.platform.
commercewebservicescommons.cache.CommerceCacheKeyGenerator).
generateKey(false,false,'getRunningCronJobCode')")
9 @ResponseBody
10 public CronJobListWsDTO getRunningCronJobCode()

Now it should take 30 seconds before any changes to cronjobs status appear
when you call our cronjob.

CMS navigation bar


SAP Hybris Accelerator CMS extension offers items to configure the top
navigation nodes :
• NavigationBarCollectionComponent, an item used to display top
navigation menu, it holds a collection of NavigationBarComponents
• NavigationBarComponents, main item type, this represents a section of
the top navigation menu, can hold a CMSNavigationNodes (to display sub
link) and a CMSLinkComponents
• CMSNavigationNodes, represents the architecture of the navigation menu,
each node can have parent nodes and children nodes
• CMSLinkComponents, represents a link, with a name and a URL
For example to create a new top navigation menu, with :
• a node with only a home link
• a node with the camera category
• a node with various external links
1 $contentCatalog=electronicsContentCatalog
2 $contentCatalogName=Electronics Content Catalog
3 $contentCV=catalogVersion(CatalogVersion.catalog(Catalog.id[default=
$contentCatalog]),CatalogVersion.version[default=Online])[default
=$contentCatalog:Online]
4 $productCatalog=electronicsProductCatalog
5 $productCatalogName=Electronics Product Catalog
6 $productCV=catalogVersion(catalog(id[default=$productCatalog]),
version[default='Staged'])[unique=true,default=$productCatalog:
Staged]
7 $category=category(code, $productCV)
8
9 #First we create a Root node
10 INSERT_UPDATE CMSNavigationNode;uid[unique=true];$contentCV[unique=
true];name;children(uid,$contentCV)[mode=append]
11 ;rootNode;;rootNode;;
12
13 #We create the needed links
14 INSERT_UPDATE CMSLinkComponent;$contentCV[unique=true];uid[unique=
true];name;url;&linkRef;&componentRef;target(code)[default='
sameWindow'];$category;
15 ;;HomepageNavLink;Home Page Nav Link;/;HomepageNavLink;
HomepageNavLink;;;
16 ;;CamerasCategoryLink;Cameras Category Link;;CamerasCategoryLink;
CamerasCategoryLink;;571;
17 ;;HackerNewsNavLink;Hacker News Page Nav Link;https://news.
ycombinator.com/news;HackerNewsNavLink;HackerNewsNavLink;;;
18 ;;GitHubNavLink;Git Hub Page Nav Link;https://github.com;
GitHubNavLink;GitHubNavLink;;;
19
20 #We Create the nodes
21 INSERT_UPDATE CMSNavigationNode;uid[unique=true];$contentCV[unique=
true];name;parent(uid, $contentCV);links(&linkRef);&nodeRef
22 ;ElectronicsNavNode;;Electronics Site;rootNode;HomepageNavLink;
ElectronicsNavNode
23 ;CamerasNavNode;;Cameras Category;rootNode;CamerasCategoryLink;
CamerasNavNode
24 ;VariousNavNode;;Various Links;rootNode;HackerNewsNavLink,
GitHubNavLink;VariousNavNode
25
26 #We create the navigation bar components
27 INSERT_UPDATE NavigationBarComponent;$contentCV[unique=true];uid[
unique=true];navigationNode(&nodeRef);&componentRef;link(uid,
$contentCV)
28 ;;ElectronicsNavComponent;ElectronicsNavNode;ElectronicsNavComponent;
HomepageNavLink
29 ;;CamerasNavComponent;CamerasNavNode;CamerasNavComponent;
CamerasCategoryLink
30 ;;VariousNavComponent;VariousNavNode;VariousNavComponent;
HomepageNavLink
31
32 #We create the navigation bar collection
33 INSERT_UPDATE NavigationBarCollectionComponent;$contentCV[unique=true
];uid[unique=true];name;components(uid, $contentCV);&componentRef
34 ;;NavBarComponent;Navigation Bar Collection Componeent;
ElectronicsNavComponent,CamerasNavComponent,VariousNavComponent;
NavBarComponent

Run this Impex query on the electronic store to update the top
navigation menu

Order splitting
Order splitting is part of the Order Management Module and is responsible of
splitting orders into different consignments based on the implemented splitting
strategy.
The service responsible for splitting orders into different consignments is
de.hybris.platform.ordersplitting.orderSplittingService, this service contains a
list of splitting strategy to apply on a given order. A strategy needs to
implement de.hybris.platform.ordersplitting.strategy.SplittingStrategy, the out
of the box strategy are :
• splitByAvailableCount
• splitByDeliveryMode
• splitByPoS
• splitByNamedDeliveryDate
• splitByEntryDeliveryAddress
• splitByWarehouse
To implement a new strategy use
de.hybris.platform.ordersplitting.strategy.AbstractSplittingStrategy,
this abstract class helps by doing most of the work, all you have to
do is to implement getGroupingObject (to select the attribute to
group order entries) and afterSplitting to create consignment.

Promotion
SAP Hybris V6 introduced a major change with the new Promotion Engine
(Running with the new rule engine), unlike the now legacy Promotion Module
which was still using the deprecated Jalo Layer, the new Promotion Engine uses
the services layer and is highly flexible.
For backward compatibility reasons under SAP Hybris V6 both
legacy Promotion Module and new Promotion Engine are available,
all new promotion implementation should be done using the
Promotion Engine
The rule engine is based on Drools

Payment
SAP Hybris provides a module to integrate external payment gateways such as
CyberSource, the module is designed to seamlessly integrate any PSP into your
checkout flow.
Since SAP Hybris V6, CyberSource payment integration is not part of
the Commerce Accelerator, you would need to add the CyberSource
extension.
When you integrate a new payment provider, you need to integrate the following
steps :
• Authorization, Authorized amount of money remains locked on card’s
account until it is captured or authorization is reversed (cancelled) or
authorization is expired
• Capture, Capturing an authorization means the authorized amount of
money is actually transferred from the card holder account to the
merchant account. Capture operation requires a previous successful
authorization that has not yet expired
• Partial Capture, Capture only a fragment of the reserved amount
• Void, cancel an on going authorization
• Follow on refund, refund money to the customer’s bank account for an
order
• Standalone refund, refund money to the customer’s bank account when
not attached to any transactions or orders
• Is applicable, command to check if the payment provider can execute a
given command
When you have implemented all commands for your payment service provider,
create a new bean using
de.hybris.platform.payment.commands.factory.impl.DefaultCommandFactoryImpl,
and inject all your commands in it.
SAP Hybris can have multiple PSP configured at the same time, it’s
up to the checkout flow to gibe the customer the option to choose the
final PSP
Internationalization
SAP Hybris supports out of the box :
• Languages (localizations of business objects)
• Countries and Regions (tax regulations)
• Currencies (currency formats, rounding)
• Time Zones (online / offline dates, order dates)
• Number Formats (separation characters)
• Language fallbacks
• Tenant-specific settings
• Localized API for the service layer
• Compatible UI to manage localized attributes
The following services to work with internationalization and localization are
available :
• de.hybris.platform.servicelayer.i18n.I18NService, service to work with
Java internationalization objects(Locale, Currency, TimeZone)
• de.hybris.platform.servicelayer.i18n.CommonI18NService, service to work
with SAP Hybris localization objects (LanguageModel, CurrencyModel,
CountryModel, RegionModel), those items can be used to create a Java
Locale object
• de.hybris.platform.servicelayer.i18n.L10NService, provides methods
localized resources bundles

de.hybris.platform.commerceservices.i18n.CommerceCommonI18NService,
provides localization objects for the current base site
internationalization is making your software compatible with
different currencies, countries…. localization is providing the
appropriate resources for a specific language

Request handling
SAP Hybris accelerators are built on top of Spring MVC, this will handle all
HTTP requests you make to SAP Hybris. Below a simplified representation of
how Spring MVC handles requests :
The dispatcherServlet (org.springframework.web.servlet.DispatcherServlet )is
responsible of handling and dispatching requests for all incoming requests it
receives.
A unique entry point is configured for each extension web module, by default
it’s the name of the extension. You can changing from your configuration (they
are intentionally empty):
1 hybhubstorefront.webroot=
2 storefrontContextRoot=

Request filters

request filters are handled by a DelegatingFilterProxy, a special servlet filter


that, by itself, doesn’t do much. Instead, it delegates to an implementation of
javax.servlet.Filter that’s registered as a bean in the Spring application context.
The accelerators are configured with different filters out of the box :
• cmsSiteFilter
• storefrontFilter
• urlEncoderFilter
• springSecurityFilterChain
• anonymousCheckoutFilter
• cartRestorationFilter
• customerLocationRestorationFilter
• ….
The filter entry point is configured inside your web application web.xml file :
1 <filter>
2 <description>
3 Spring configured chain of spring filter beans in tenant
scope
4 </description>
5 <filter-name>storefrontTenantFilterChain</filter-name>
6 <filter-class>org.springframework.web.filter.
DelegatingFilterProxy</filter-class>
7 </filter>

The bean storefrontTenantFilterChain is configured inside your extension spring-


filter-config.xml :
1 <bean id="storefrontTenantFilterChain" class="com.hybhub.storefront.
filters.UrlPathFilter" >
2 <property name="defaultFilter" ref="
storefrontTenantDefaultFilterChain"/>
3 <property name="urlPathHelper">
4 <bean class="org.springframework.web.util.UrlPathHelper"/>
5 </property>
6 <property name="urlPathMapping">
7 <map>
8 <entry key="/integration/" value-ref="
integrationTenantFilterChain"/>
9 </map>
10 </property>
11 </bean>

Create a new request filter

Create a new class :


1 package com.hybhub.storefront.filters;
2

3 import java.io.IOException;
4

5 import javax.servlet.FilterChain;
6 import javax.servlet.ServletException;
7 import javax.servlet.ServletRequest;
8 import javax.servlet.ServletResponse;
9 import javax.servlet.http.HttpServletRequest;
10

11 import org.slf4j.Logger;
12 import org.slf4j.LoggerFactory;
13 import org.springframework.web.filter.GenericFilterBean;
14

15 public class HybhubFilter extends GenericFilterBean


16 {
17

18 Logger LOG = LoggerFactory.getLogger(HybhubFilter.class);


19

20 @Override
21 public void doFilter(final ServletRequest paramServletRequest,
final ServletResponse paramServletResponse,
22 final FilterChain paramFilterChain) throws IOException,
ServletException
23 {
24 final HttpServletRequest httpRequest = (HttpServletRequest)
paramServletRequest;
25

26 LOG.debug("Request received by the filter " + this.


getFilterName());
27 LOG.debug("Requested path was " + httpRequest.getPathInfo());
28

29 paramFilterChain.doFilter(paramServletRequest,
paramServletResponse);
30 }
31

32 }

Then update your storefront spring-filter-config.xml file with :


1 <bean id="hybhubFilter" class="com.hybhub.storefront.filters.
HybhubFilter" />
2
3 <alias name="defaultStorefrontTenantDefaultFilterChainList" alias="
storefrontTenantDefaultFilterChainList" />
4 <util:list id="defaultStorefrontTenantDefaultFilterChainList">
5 <!-- other filters -->
6 <ref bean="hybhubFilter"/>
7 <!-- other filters -->
8 </util:list>

The order you place your filter matters as they are executed in the
list order!

Hot folders
SAP Hybris provides different ways to import data, one of them is a hot folder.
A hot folder means that when you transfer a file into a specific folder with
matching name it will automatically be processed by SAP Hybris.
The hot folder functionality is located inside the acceleratorservices
extension, it’s based on the Spring Integration Framework
When you transfer a file into a hot folder, the following actions are executed :
1. an inbound channel detects a new file matching a pattern (file:inbound-
channel-adapter)
2. an outbound channel moves the file to a new folder (file:outbound-gateway)
3. activators setup the headers (int:service-activator)
4. resolve the mapping between the file name and the type to import
5. generate the impex
6. run the impex
7. cleanup

Create a new import configuration

Let’s assume the out of the box customer import flow is not enough for us, we
need a new one with a different header and more attributes.

Create a inbound, outbound, mapping and converter

1 <file:inbound-channel-adapter id="hybhubBatchFilesCustomer" directory


="#{baseDirectoryTenant}"
2 filename-regex="^customers_full\-(.*)-(\d+)\.csv" comparator="
fileOrderComparator">
3 <int:poller fixed-rate="1000" />
4 </file:inbound-channel-adapter>
5
6 <file:outbound-gateway request-channel="hybhubBatchFilesCustomer"
reply-channel="hybhubBatchFilesCustomerProc"
7 directory="#{baseDirectoryTenant}/processing" delete-source-files
="true" />
8
9 <bean id="hybhubCustomersHeaderSetupTask" class="de.hybris.platform.
acceleratorservices.dataimport.batch.task.HeaderSetupTask">
10 <property name="catalog" value="electronicsProductCatalog" />
11 <property name="net" value="false" />
12 <property name="storeBaseDirectory" ref="baseDirectoryTenant" />
13 </bean>
14
15 <int:service-activator input-channel="hybhubBatchFilesCustomerProc"
output-channel="batchFilesHeaderInit"
16 ref="hybhubCustomersHeaderSetupTask" method="execute" />
17
18 <bean id="hybhubBatchCustomerConverterMapping"
19 class="de.hybris.platform.acceleratorservices.dataimport.batch.
converter.mapping.impl.DefaultConverterMapping"
20 p:mapping="customers_full"
21 p:converter-ref="hybhubBatchCustomerConverter"/>
22
23 <bean id="hybhubBatchCustomerConverter" class="de.hybris.platform.
acceleratorservices.dataimport.batch.converter.impl.
DefaultImpexConverter">
24 <property name="header">
25 <value>#{defaultImpexProductHeader}
26 # Insert Customer
27 $defaultPassword=1234
28 $setName=name[cellDecorator=de.hybris.platform.
acceleratorservices.dataimport.batch.decorator.
CustomerNameDecorator]
29 INSERT_UPDATE Customer;uid[unique=true];$setName;title(
code);sessionLanguage(isocode);sessionCurrency(
isocode);groups(uid)
30 </value>
31 </property>
32 <property name="impexRow">
33 <value>;{+0};{1} {2};{3};{4};{5};{6}</value>
34 </property>
35 </bean>

Here we are using headerInitTask as a batchFilesHeaderInit, this is expecting


your file to match the following pattern to extract the language code:
1 -(\w{2})-(\d+)\.csv

And this to extract the sequence:


1 -(\d+)\.csv

Create a file under data/acceleratorservices/import/master named


customers_full-en-0.csv with the following content :
1 [email protected],Serge,Dupont,mr,en,USD,regulargroup

This file will be automatically executed by SAP Hybris, and a new customer
will be created.
The mapping is made between the name of your file and the string
property of the ConverterMapping implementation
Impex row definition uses a strange syntax, try to remember that +
means mandatory and ‘S’ means the current sequence ID

Data Modeling

Create new types

SAP Hybris gives you the ability to extend the existing model definition, this
way you can completely customize the SAP Hybris platform with your own
types, your own attributes for existing types and your own relations between
types.
All types definition are done using XML item files, from extensions with a core
module :
1 <coremodule generated="true"
2 manager="de.hybris.platform.jalo.extension.GenericManager"
packageroot="com.hybhub.myextension"/>

The definitions are located under resources/myextension-items.xml, example of


an empty definition :
1 <?xml version="1.0" encoding="ISO-8859-1"?>
2 <!--
3 ~ [y] hybris Platform
4 ~
5 ~ Copyright (c) 2000-2016 SAP SE
6 ~ All rights reserved.
7 ~
8 ~ This software is the confidential and proprietary information of
SAP
9 ~ Hybris ("Confidential Information"). You shall not disclose such
10 ~ Confidential Information and shall use it only in accordance with
the
11 ~ terms of the license agreement you entered into with SAP Hybris.
12 -->
13 <!--
14 ATTENTION: This is just an example file. You have to edit it
according to your needs.
15 -->
16
17 <items xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
18 xsi:noNamespaceSchemaLocation="items.xsd">
19
20 <itemtypes>
21 <!--
22 <itemtype generate="true"
23 code="MyProduct"
24 jaloclass="yemptypackage.jalo.MyProduct"
25 extends="Product"
26 autocreate="true"
27 >
28 <attributes>
29 <attribute qualifier="myExampleInitialStringField"
type="java.lang.String">
30 <description>My Example Initial String Value</
description>
31 <modifiers initial="true"/>
32 <persistence type="property"/>
33 </attribute>
34
35 <attribute qualifier="myExampleBooleanField" type="
java.lang.Boolean">
36 <description>Example Initial Boolean Field</
description>
37 <persistence type="property"/>
38 </attribute>
39
40 <attribute qualifier="media" type="Media">
41 <persistence type="property"/>
42 </attribute>
43
44 </attributes>
45 </itemtype>
46 -->
47 </itemtypes>
48 </items>

From an *-items.xml file you can declare different item types :


• Atomic types, the most basic types available on the SAP Hybris
platform, they most likely represent Numbers, Strings, Dates…. they
have a direct correspondence with a database type.You probably won’t
need to define your own Atomic type, following is an example extracted
from core-items.xml :
xml <atomictype class="java.lang.Double" extends="java.lang.
Number" autocreate="true" generate="false"/>
• Collection types, special attributes to store a list of element n the form of a
String containing PKs of all contained elements, think about the collection
type in SAP Hybris as a backpack mounted onto a type. On the database
level collection types are represented as a commas separated list of PKs,
following is an example extracted from core-items.xml :
“‘xml
“‘
• Enumeration types, they are like java Enumerations, they declare a
collection of constants, within SAP Hybris Enumeration is a composed
type and their value represents their instance. Within SAP Hybris
enumerations can be dynamic, meaning you can add new values during
runtime (unlike enumerations in Java), following is an example extracted
from core-items.xml :
1 <enumtype code="OrderStatus" autocreate="true" generate="true"
dynamic="true">
2 <value code="CREATED"/>
3 <value code="ON_VALIDATION"/>
4 <value code="COMPLETED"/>
5 <value code="CANCELLED"/>
6 </enumtype>

• Map types, they are type collections of key/value pairs, they are
intensively used under SAP Hybris for localized elements, for example
when you use localized:java.lang.String, following is an example extracted
from core-items.xml :
1 <maptype code="localized:java.lang.String"
2 argumenttype="Language"
3 returntype="java.lang.String"
4 autocreate="true"
5 generate="false"/>

• Relation types, they are the way to go to represent n:m relations, internally
SAP Hybris links both element via an instance of an helper type called
LinkedItem. LinkedItem holds 2 attributes, SourceItem and TargetItem.
When SAP Hybris runs a search query on either side of the relation it
returns a java Collection that contain all values, following is an example
extracted from core-items.xml :
1 <relation code="Country2RegionRelation" generate="true" localized="
false" autocreate="true">
2 <sourceElement type="Country" qualifier="country" cardinality="
one">
3 <modifiers read="true" write="true" search="true" optional="
false" unique="true"/>
4 </sourceElement>
5 <targetElement type="Region" qualifier="regions" cardinality="
many">
6 <modifiers read="true" write="true" search="true" partof="
true"/>
7 </targetElement>
8 </relation>

• Item types, also called composed types are the main type used to build
SAP Hybris platform, all types are derived of a ComposedType. It holds
metadata about the types like the item’s type code, the JNDI deployment
location, the database table deployment and the type’s java class, following
is an example extracted from core-items.xml :
1 <itemtype code="Title"
2 extends="GenericItem"
3 jaloclass="de.hybris.platform.jalo.user.Title"
4 autocreate="true"
5 generate="true">
6 <!-- deployment="de.hybris.platform.persistence.user.Title" -->
7 <deployment table="Titles" typecode="24"/>
8 <attributes>
9 <attribute autocreate="true" qualifier="code" type="java.lang
.String">
10 <persistence type="property"/>
11 <modifiers read="true" write="true" search="true" initial
="true" optional="false" unique="true"/>
12 <custom-properties>
13 <property name="hmcIndexField">
14 <value>"thefield"</value>
15 </property>
16 </custom-properties>
17 </attribute>
18 <attribute autocreate="true" qualifier="name" type="localized
:java.lang.String">
19 <modifiers read="true" write="true" search="true"
optional="true"/>
20 <persistence type="property"/>
21 <custom-properties>
22 <property name="hmcIndexField">
23 <value>"thefield"</value>
24 </property>
25 </custom-properties>
26 </attribute>
27 </attributes>
28
29 <indexes>
30 <index name="codeIdx">
31 <key attribute="code"/>
32 </index>
33 </indexes>
34 </itemtype>

Exercise, design your own data types

Our main objective here is to model a blog as we want to add the ability for our
employees to blog about new products and the company :
We have posts, they represent the content of each blog entry, each post is linked
to a blog linked to one or more CMSSites, each posts can have comments linked
to users.
First we need enum types : * for post status (draft, published, deleted) * for
comment status (pending, approved, blocked)
1 <enumtypes>
2 <enumtype code="PostStatus">
3 <value code="DRAFT"/>
4 <value code="PUBLISHED"/>
5 <value code="DELETED"/>
6 </enumtype>
7 <enumtype code="CommentStatus">
8 <value code="PENDING"/>
9 <value code="APPROVED"/>
10 <value code="BLOCKED"/>
11 </enumtype>
12 </enumtypes>

Then we create the new item types : * Post * Blog * PostComment


When you create new item types it is mandatory to specify a
deployment table, or the build would fail (you can deactivate this
check with build.development.mode=false)
1 [ycheckdeployments] No deployment defined for non-abstract itemType
Blog in file:
2 /Users/b.vanalderweireldt/.../resources/hybhubaddon-items.xml

1 <itemtypes>
2 <itemtype code="Blog" extends="GenericItem" autocreate="true"
generate="true">
3 <deployment table="blog" typecode="11001" />
4 <attributes>
5 <attribute qualifier="code" type="java.lang.String">
6 <modifiers initial="true" read="true" write="false"
optional="false" unique="true" />
7 <persistence type="property" />
8 </attribute>
9 <attribute qualifier="active" type="boolean">
10 <persistence type="property" />
11 </attribute>
12 </attributes>
13 </itemtype>
14
15 <itemtype code="Post" extends="GenericItem" autocreate="true"
generate="true">
16 <deployment table="post" typecode="11002" />
17 <attributes>
18 <attribute qualifier="blog" type="Blog">
19 <persistence type="property"/>
20 </attribute>
21 <attribute qualifier="date" type="java.util.Date">
22 <modifiers optional="false"/>
23 <persistence type="property" />
24 </attribute>
25 <attribute qualifier="author" type="Employee">
26 <modifiers optional="false"/>
27 <persistence type="property" />
28 </attribute>
29 <attribute qualifier="title" type="localized:java.lang.
String">
30 <persistence type="property" />
31 </attribute>
32 <attribute qualifier="content" type="localized:java.lang.
String">
33 <persistence type="property">
34 <columntype>
35 <value>HYBRIS.LONG_STRING</value>
36 </columntype>
37 </persistence>
38 <modifiers search="false"/>
39 </attribute>
40 <attribute qualifier="keywords" type="StringCollection">
41 <persistence type="property" />
42 </attribute>
43 <attribute qualifier="status" type="PostStatus">
44 <persistence type="property" />
45 <defaultvalue>em().getEnumerationValue("PostStatus",
"DRAFT")</defaultvalue>
46 </attribute>
47 </attributes>
48 </itemtype>
49
50 <itemtype code="PostComment" extends="GenericItem" autocreate="
true" generate="true">
51 <deployment table="postcomment" typecode="11003" />
52 <attributes>
53 <attribute qualifier="author" type="User">
54 <persistence type="property"/>
55 </attribute>
56 <attribute qualifier="content" type="java.lang.String">
57 <persistence type="property">
58 <columntype>
59 <value>HYBRIS.LONG_STRING</value>
60 </columntype>
61 </persistence>
62 <modifiers search="false" optional="false"/>
63 </attribute>
64 <attribute qualifier="status" type="CommentStatus">
65 <persistence type="property" />
66 </attribute>
67 </attributes>
68 </itemtype>
69 </itemtypes>

We finally need to create relations * between Blog and CMSSIte


1 <relation localized="false" code="BlogCMSSiteRelation">
2 <deployment table="blogcmssiterelation" typecode="1201"/>
3 <sourceElement type="Blog" qualifier="blogs" cardinality="many"/>
4 <targetElement type="CMSSite" qualifier="sites" cardinality="many
"/>
5 </relation>

When you run ant all the SAP Hybris platform, the build framework will :
• Generate Model classes for the service layer (for example BlogModel)
• Abstract Jalo layer classes, starting with Generated (for example
GeneratedBlog)
• Non abstract Jalo layer classes, with the same name than the item type
(for example Blog)
Jalo is deprecated since Hybris V4.3, however not all logic have been
moved to the service layer. If you don’t plan to use the Jalo layer
with your item types you can use generate=“false”
Once you have build the platform successfully, you will need to update your
system so SAP Hybris can update the database with the new item types
definition (using the HAC or ant initialize). Check that all new types,
relations and enumtypes are available from the backoffice (filter types per
extension, in my case they are under hybhubaddon extension):
We can see that all newly defined items are available in our current system.

Import test data

1 INSERT_UPDATE Blog;code[unique=true];active[default=true]
2 ;myBlog;
3
4 INSERT_UPDATE Post;date[unique=true][dateformat=dd-MM-yyyy];Blog(code
);author(uid)
5 ;01-01-2016;myBlog;admin
6
7 INSERT_UPDATE PostComment;content[unique=true];author(uid);status(
code);
8 ;This is the content;admin;PENDING

Extend existing types

SAP Hybris not only gives you the ability to create new types, but also gives
you the ability to extend the core item types (User, Product,…) without
changing any of the core extensions so you would be able to update SAP
Hybris without breaking anything. This is one of the greatest feature of SAP
Hybris the possibility of building your e-commerce platform not from SAP
Hybris but on top of the existing code.
Let’s do two examples of how we can extend existing item types :
• Users will have a birthday attribute
• Products will have a boolean to activate or not an export to Google
Shopping
1 <itemtype code="Product" autocreate="false" generate="false">
2 <attributes>
3 <attribute qualifier="exportToGoogleShopping" type="java.lang
.Boolean">
4 <persistence type="property"/>
5 </attribute>
6 </attributes>
7 </itemtype>
8
9 <itemtype code="Customer" autocreate="false" generate="false">
10 <attributes>
11 <attribute qualifier="birthday" type="java.util.Date">
12 <persistence type="property"/>
13 </attribute>
14 </attributes>
15 </itemtype>

Update your system and check from the backoffice that new attributes have
been added to your types :
New attributes are also available from the model service.

Localized Attributes

Localized attribute type is an essential type under SAP Hybris platform, it gives
you the ability to dynamically server different content (text, image, link…) based
on the user language.
An example would be the product name :
1 <attribute autocreate="true" qualifier="name" type="localized:java.
lang.String">
2 <modifiers read="true" write="true" search="true" optional="true"
/>
3 <persistence type="property"/>
4 <custom-properties>
5 <property name="hmcIndexField">
6 <value>"thefield"</value>
7 </property>
8 </custom-properties>
9 </attribute>

When an item type has a localized attribute, SAP Hybris will automatically
create an extra database table ending with lp, for example Product type has
the table productslp :
1 MariaDB [database]> explain productslp;
2 +-----+--------------+------+-----+---------+-------+
3 | Field | Type | Null | Key | Default
| Extra |
4 +-----+--------------+------+-----+---------+-------+
5 | ITEMPK | bigint(20) | NO | PRI | 0
| |
6 | ITEMTYPEPK | bigint(20) | YES | | NULL
| |
7 | LANGPK | bigint(20) | NO | PRI | 0
| |
8 | p_name | varchar(255) | YES | | NULL
| |
9 | p_description | text | YES | | NULL
| |
10 | p_manufacturertypedescription | varchar(255) | YES | | NULL
| |
11 | p_segment | varchar(255) | YES | | NULL
| |
12 | p_articlestatus | longblob | YES | | NULL
| |
13 | p_summary | text | YES | | NULL
| |
14 | p_directionofuse | text | YES | | NULL
| |
15 | p_specialpricedescription | text | YES | | NULL
| |
16 | p_style | varchar(255) | YES | | NULL
| |
17 | p_size | varchar(255) | YES | | NULL
| |
18 | p_color | varchar(255) | YES | | NULL
| |
19 +-----+--------------+------+-----+---------+-------+
20 14 rows in set (0.01 sec)

Each localized attribute of an item are grouped in this table and linked to a
language through LANGPK.
The model service will create getters and setters like this :
1 /**
2 * <i>Generated method</i> - Getter of the <code>Product.description
</code> attribute defined at extension <code>core</code>.
3 * @return the description
4 */
5 @Accessor(qualifier = "description", type = Accessor.Type.GETTER)
6 public String getDescription()
7 {
8 return getDescription(null);
9 }
10 /**
11 * <i>Generated method</i> - Getter of the <code>Product.description
</code> attribute defined at extension <code>core</code>.
12 * @param loc the value localization key
13 * @return the description
14 * @throws IllegalArgumentException if localization key cannot be
mapped to data language
15 */
16 @Accessor(qualifier = "description", type = Accessor.Type.GETTER)
17 public String getDescription(final Locale loc)
18 {
19 return getPersistenceContext().getLocalizedValue(DESCRIPTION, loc
);
20 }

You can get the product description using a Locale object or not, if you don’t
provide any SAP Hybris will load the default one (see
de.hybris.platform.servicelayer.model.ItemModelContextImpl).

How to declare a localized attribute


localized attributes are maps, they are declared under core-items.xml :
1 <maptype code="localized:java.lang.String"
2 argumenttype="Language"
3 returntype="java.lang.String"
4 autocreate="true"
5 generate="false"/>
6 <maptype code="localized:java.lang.Integer"
7 argumenttype="Language"
8 returntype="java.lang.Integer"
9 autocreate="true"
10 generate="false"/>
11 <maptype code="localized:java.lang.Boolean"
12 argumenttype="Language"
13 returntype="java.lang.Boolean"
14 autocreate="true"
15 generate="false"/>
16 ....

Therefore to declare an attribute as localized, first check if the type has a


declared localized equivalent (SAP Hybris 6 has all atomic types, bigInteger,
bigDecimal, date range and media).
If not you could create your own localized type, for example let say you need to
localize groups :
1 <maptype code="localized:Group"
2 argumenttype="Language"
3 returntype="UserGroup"
4 autocreate="true"
5 generate="false"/>

Enumerations

SAP Hybris gives you the possibility to use attributes with a predefined list of
possible values. This works exactly like Java enumeration but at a database
level.
Enumeration types within SAP Hybris could be dynamic, it means
you could add new values during runtime. If you configure your
enumeration not to be dynamic SAP Hybris will use standard Java
enumeration instead of SAP Hybris enumerations
How to create a new enumeration ? Add it under the targeted items.xml file:
1 <enumtype code="OrderStatus" autocreate="true" generate="true"
dynamic="true">
2 <value code="CREATED"/>
3 <value code="ON_VALIDATION"/>
4 <value code="COMPLETED"/>
5 <value code="CANCELLED"/>
6 </enumtype>

You can add new values from a different extension if needed, for example the
OrderStatus enumeration is defined within the core extension, from my extension
hybhubaddon I’m adding a new value :
1 <enumtype code="OrderStatus" autocreate="false" generate="false"
dynamic="true">
2 <value code="MYSTATUS"/>
3 </enumtype>

Enumeration Service
SAP Hybris provides a service to deal with enumeration,
de.hybris.platform.enumeration.EnumerationService, here is an example
(Groovy compatible) to get the new OrderStatus we just created (you need to
build and update your SAP Hybris platform) :
1 import de.hybris.platform.enumeration.EnumerationService;
2 import de.hybris.platform.core.enums.OrderStatus;
3

4 EnumerationService es = spring.getBean("enumerationService");
5 OrderStatus os = es.getEnumerationValue("ORDERSTATUS", "MYSTATUS");
6 println os.getCode();

Dynamic attributes

In some cases, you will need dynamic attributes, for example under the address
model you have one field for each address characteristics, it would be nice to
have directly under your model object a getter for a formatted address string,
right? That’s when you use a dynamic attribute when you need attributes on
your data model objects which aren’t persisted to the database.
Use dynamic attributes to:
• Format data like addresses or names
• Create a calculated field
• Combine multiple non dynamic attributes
Don’t use a dynamic attribute to:
• Integrate your model with any external systems or database
• Trigger any intensive operation, it would slow down the platform as getters
and setters are frequently called by the cache mechanism
• Implement your own SQL query

Implement a dynamic attribute


You will need to:
• Create a value provider, it musts implement ‘DynamicAttributeHandler’
interface
• Write the logic for the getter nor the setter
• Write the value provider using Spring
• Add the value provider under your item xml definition file, setting the
persistence to dynamic with the attribute handler parameter equal to your
spring bean
• If you just need the getter nor the setter you can customize the modifier
attribute
Let’s add a dynamic attribute to our PostComment item type, we want to have
a summary of each comment with something like “PENDING - Luke T - Hi, I
recently bought a new camera to start doing prof…” :
1 <itemtype code="PostComment" extends="GenericItem" autocreate="true"
generate="true">
2 <deployment table="postcomment" typecode="11003" />
3 <attributes>
4 <attribute qualifier="author" type="User">
5 <persistence type="property"/>
6 </attribute>
7 <attribute qualifier="content" type="java.lang.String">
8 <persistence type="property">
9 <columntype>
10 <value>HYBRIS.LONG_STRING</value>
11 </columntype>
12 </persistence>
13 <modifiers search="false" optional="false"/>
14 </attribute>
15 <attribute qualifier="status" type="CommentStatus">
16 <persistence type="property" />
17 </attribute>
18 <attribute qualifier="summary" type="java.lang.String">
19 <persistence type="dynamic" attributeHandler="
dynamicAttributesPostCommentSummaryHandler"/>
20 </attribute>
21 </attributes>
22 </itemtype>

Attribute Handler value is the name of the Spring bean that is


responsible for the dynamic attribute.
Next step is to create the class to handle the dynamic attribute, we will call it
‘DynamicAttributesPostCommentSummaryHandler’:
1 package com.hybhub.hybhubaddon.servicelayer.dynamicattributes;
2 import de.hybris.platform.servicelayer.model.attribute.
DynamicAttributeHandler;
3 import com.hybhub.hybhubaddon.model.PostCommentModel;
4

5 public class DynamicAttributesPostCommentSummaryHandler implements


DynamicAttributeHandler<String, PostCommentModel>
6 {
7

8 final static String SEP = " - ";


9 final static int MAX_CONTENT = 100;
10

11 @Override
12 public String get(final PostCommentModel postComment)
13 {
14 final StringBuilder sb = new StringBuilder(postComment.
getStatus().getCode());
15 sb.append(SEP);
16 sb.append(postComment.getAuthor().getDisplayName());
17 sb.append(SEP);
18 sb.append(postComment.getContent().length() > MAX_CONTENT ?
postComment.getContent().substring(0, MAX_CONTENT)
19 : postComment.getContent());
20

21 return sb.toString();
22 }
23

24 @Override
25 public void set(final PostCommentModel postComment, final String
str)
26 {
27 throw new IllegalAccessError("Cannot set that attribute [
Summary]");
28 }
29

30 }

This class needs to implement ‘DynamicAttributeHandler’ interface, it will


provide two methods, a getter and a setter, here we will just use the getter
and thrown an exception if the setter is used. Next step is to register this
newly created class in a bean context:
1 <bean id="dynamicAttributesPostCommentSummaryHandler" class="com.
hybhub.hybhubaddon.servicelayer.dynamicattributes.
DynamicAttributesPostCommentSummaryHandler" />

And then build and run an update on your system, to try it we will use a groovy
script, go to http://localhost:9001/console/scripting/ :
1 import com.hybhub.hybhubaddon.model.PostCommentModel
2 import de.hybris.platform.servicelayer.model.ModelService
3 import de.hybris.platform.servicelayer.search.FlexibleSearchService
4 import java.util.List
5 import de.hybris.platform.servicelayer.user.UserService
6

7 UserService us = spring.getBean("userService")
8 ModelService ms = spring.getBean("modelService")
9 FlexibleSearchService fss = spring.getBean("flexibleSearchService")
10

11 PostCommentModel pcm = ms.create(PostCommentModel.class)


12 pcm.setAuthor(us.getAdminUser())
13

14 List<PostCommentModel> pcms = fss.getModelsByExample(pcm)


15 println pcms.get(0).getSummary()

If you open the output tab you should see : PENDING - Administrator - This
is the content of the PostComment
Indices & Deployment

Deployment
SAP Hybris item types are stored inside database’s tables, each instance is
stored as one row within the database.
The database table where instances of a type are stored is called the type
deployment and is specified within items.xml files. Every type must have a
deployment table to store its instances. Types inherits deployment tables from
their super types. The deployment that is active for a given type is the
deployment specified closest to the type in the type’s hierarchy. The topmost
deployment is GenericItem, which is therefore the default deployment. This
means if a type has no explicit specification of deployment, that type’s
instances are deployed in the same table as GenericItem.
This means that the default deployment of any subtype, which you extend from
GenericItem, is the deployment of GenericItem. In other words: if you do not
specify a deployment for a subtype of GenericItem, the instances of that subtype
are stored in the same table as instances of GenericItem.
For example, the User and Product types in SAP Hybris Commerce are subtypes
of GenericItem. If there were no deployment specified for User and Product, all
Users and Products instances would be written into one single database table.
Firstly, this is not intuitive. Secondly, storing instances of many different types
in one single database table causes that database table to have quite a lot
of columns to store all attributes from all these types (a User has different
attributes than a Product, and both types need to store attribute values).
Not declaring a deployment table for a new item type (extending
GenericItem) would lead the build to fail : [ycheckdeployments] No
deployment defined for relation in file: If you want to force this
behavior besides the performance and schema complexity bottlenecks
you could use : build.development.mode=true
To specify your own deployment table:
1 <itemtype code="Blog" extends="GenericItem" autocreate="true"
generate="true">
2 <deployment table="blog" typecode="11001" />
3 ...
4 </itemtype>

The deployment attribute also has a propertytable attribute, this is to configure


different advanced database features (database attribute types).

Indices
SAP Hybris gives you the ability to add database indices on item types, indices
have a name and one or more key (composite indices), here is an example of an
index on the blog type:
1 <indexes>
2 <index name="blogIDX" unique="true">
3 <key attribute="code" lower="true"/>
4 <key attribute="active"/>
5 </index>
6 </indexes>

SAP Hybris will run the following SQL command (may vary upon the targeted
database, here we use HSQL):
1 CREATE UNIQUE INDEX blogIDX_11001 ON BLOG (P_CODE, P_ACTIVE);

Types in DB

When SAP Hybris generates the SQL commands to initialize the system, it will
select the right destination types based on the current database, there is a out of
the box mapping for this, have a look at the file core-advanced-deployment.xml,
for example for Mysql :
1 <database-schema database="mysql" primary-key="primary key" null=""
not-null="not null" >
2 <type-mapping type="java.lang.String" persistence-type="varchar
(255)" />
3 <type-mapping type="String" persistence-type="varchar(255)" />
4
5 <type-mapping type="java.lang.Float" persistence-type="float
(20,5)" />
6 <type-mapping type="java.lang.Double" persistence-type="double" /
>
7 <type-mapping type="java.lang.Byte" persistence-type="smallint" /
>
8 <type-mapping type="java.lang.Character" persistence-type="
smallint" />
9 <type-mapping type="java.lang.Short" persistence-type="integer" /
>
10 <type-mapping type="java.lang.Boolean" persistence-type="tinyint
(1)" />
11 <type-mapping type="java.lang.Long" persistence-type="bigint" />
12 <type-mapping type="java.lang.Integer" persistence-type="integer"
/>
13
14 <type-mapping type="float" persistence-type="float(20,5) DEFAULT
0" />
15 <type-mapping type="double" persistence-type="double DEFAULT 0" /
>
16 <type-mapping type="byte" persistence-type="smallint DEFAULT 0" /
>
17 <type-mapping type="char" persistence-type="smallint DEFAULT 0" /
>
18 <type-mapping type="short" persistence-type="integer DEFAULT 0" /
>
19 <type-mapping type="boolean" persistence-type="tinyint(1) DEFAULT
0" />
20 <type-mapping type="long" persistence-type="bigint DEFAULT 0" />
21 <type-mapping type="int" persistence-type="integer DEFAULT 0" />
22
23 <type-mapping type="java.util.Date" persistence-type="datetime" /
>
24 <type-mapping type="java.math.BigDecimal" persistence-type="
DECIMAL(30,8)" />
25 <type-mapping type="java.io.Serializable" persistence-type="
LONGBLOB" />
26
27 <type-mapping type="HYBRIS.LONG_STRING" persistence-type="TEXT" /
>
28 <type-mapping type="HYBRIS.COMMA_SEPARATED_PKS" persistence-type=
"TEXT" />
29 <type-mapping type="HYBRIS.PK" persistence-type="BIGINT" />
30 </database-schema>

To see what commands SAP Hybris uses to creates your item types you can use
the dry-run functionality (Dry Run), for example for our Post type on HSQL
SAP Hybris will execute :
1 CREATE CACHED TABLE post
2 (
3 hjmpTS BIGINT,
4 createdTS TIMESTAMP,
5 modifiedTS TIMESTAMP,
6 TypePkString BIGINT,
7 OwnerPkString BIGINT,
8 PK BIGINT NOT NULL,
9 p_blog BIGINT,
10 p_date TIMESTAMP,
11 p_author BIGINT,
12 p_keywords LONGVARBINARY,
13 p_status BIGINT,
14 aCLTS BIGINT DEFAULT 0,
15 propTS BIGINT DEFAULT 0,
16 PRIMARY KEY (PK)
17 );
18 CREATE CACHED TABLE postlp
19 (
20 ITEMPK BIGINT,
21 ITEMTYPEPK BIGINT,
22 LANGPK BIGINT,
23 p_title NVARCHAR(255),
24 p_content LONGVARCHAR,
25 PRIMARY KEY (ITEMPK, LANGPK)
26 );

Flexible Search Query

FSQL or flexible search query language helps you looking for items and types
using a SQL-like syntax. Why SAP Hybris is doing this? SAP Hybris is
compatible with Various Databases (HSQL, Mysql, Oracle and Microsoft SQL
Server) but each of them implements a different SQL version, SAP Hybris
needed to have a database abstraction layer, allowing you to write a FSQL
query that would run on any compatible databases (SAP Hana, Mysql, SQL
Server, HSQL, Postgres). It abstracts from you details such as column and
table names and it is translated into native SQL statements on execution.
allowing nearly every aspect of SQL SELECT statements (but no data
manipulation is possible, update or delete are not available).
Flexible Search Queries are only for search, they cannot do any SQL
DML or SQL DDL queries
Flexible Search Queries are executed on the database trough a SQL
query, therefore it is not possible to flexible search queries on Jalo or
dynamic attributes

Cache
SAP Hybris is caching flexible search query results, that is the reason why you
should always deactivate the query cache on your database when you go on
production. On Mysql it’s deactivated by default, but if you are not sure simply
add this line to your my.cnf configuration:
1 query_cache_size=0

Session and restrictions


Flexible search queries are executed in a session context, different factors can
influence the number of search results:
• The session user, by default the session is assigned the anonymous user,
you could assign the session to any available user (including admin user)
• Restrictions, they are fragments of the SQL where clause that are applied
for a given item type. No restrictions are applied when you run a flexible
search query with an admin session.

Restrictions
Restrictions are manageable from the SearchRestrictionService:
1 package de.hybris.platform.search.restriction;
2

3 import de.hybris.platform.core.model.security.PrincipalModel;
4 import de.hybris.platform.core.model.type.ComposedTypeModel;
5 import de.hybris.platform.core.model.type.SearchRestrictionModel;
6 import de.hybris.platform.search.restriction.session.
SessionSearchRestriction;
7 import java.util.Collection;
8

10 public interface SearchRestrictionService


11 {
12 void addSessionSearchRestrictions(Collection<
SessionSearchRestriction> arg0);
13 void addSessionSearchRestrictions(SessionSearchRestriction...
arg0);
14 void clearSessionSearchRestrictions();
15 void disableSearchRestrictions();
16 void enableSearchRestrictions();
17 Collection<SearchRestrictionModel> getActiveSearchRestrictions(
PrincipalModel arg0, boolean arg1,
18 Collection<ComposedTypeModel> arg2);
19 Collection<SearchRestrictionModel> getInactiveSearchRestrictions(
PrincipalModel arg0, boolean arg1,
20 Collection<ComposedTypeModel> arg2);
21 Collection<SearchRestrictionModel> getSearchRestrictions(
PrincipalModel arg0, boolean arg1,
22 Collection<ComposedTypeModel> arg2);
23 Collection<SearchRestrictionModel> getSearchRestrictionsForType(
ComposedTypeModel arg0);
24 Collection<SessionSearchRestriction> getSessionSearchRestrictions
();
25 Collection<SessionSearchRestriction> getSessionSearchRestrictions
(ComposedTypeModel arg0);
26 boolean hasRestrictions(PrincipalModel arg0, boolean arg1,
ComposedTypeModel arg2);
27 boolean isSearchRestrictionsEnabled();
28 void removeSessionSearchRestrictions(Collection<
SessionSearchRestriction> arg0);
29 void removalAllSessionSearchRestrictions();
30 }

You could activate or deactivate the search restriction from the restriction
service, or create/update/delete existing restrictions.
Another way to create restrictions is Impex:
1 INSERT_UPDATE SearchRestriction;code[unique=true];name[lang=en];query
;principal(UID);restrictedType(code);active;generate
2 ;Restriction_Code;Restriction Name;{Active} = true;anonymous;Language
;true;true

Here we create a restriction for anonymous users, they would see only the active
languages. For example when you run this flexible search query (anonymous
user):
1 select {name} from {Language}

SAP Hybris will execute this SQL query (*pay attention to the WHERE clause
where our restriction is added):
1 SELECT lp_t0.p_name FROM languages item_t0 JOIN languageslp lp_t0
2 ON item_t0.PK = lp_t0.ITEMPK AND lp_t0.LANGPK =?
3 WHERE (item_t0.TypePkString=? AND ( item_t0.p_active = true))

You could also create restriction from the hmc or the backoffice, they are called
Personalization Rule

Syntax
Flexible search queries are very similar to SQL queries, although it is dedicated
only for search. It abstracts all the database details (columns and tables name),
it is translated into native SQL query on execution. The basic syntax of a
flexible search query looks like this:
1 SELECT <selects> FROM <types> ( WHERE <conditions> )? ( ORDER BY <
order> )?

• Select is mandatory
• types is mandatory
• conditions is optional
• order is optional
All standard select SQL keywords are available (ORDER BY,AS,IS NULL,…)
and you also need to remember this:
• By default SAP Hybris will search for the given type and any subtype, if
you want the query only to search for the given item type you need to use
an exclamation mark, select {code} from {Product!}
• JOIN can be made inside the curly braces, {Product as prd join PriceRow
as price on {prd:code} = {price:productId}}
• WHERE clauses can execute sub queries using double curly braces **
• To work with localized attributes you need to specify the language
{Name[en]} to select an attribute. If you want to match a localized
attribute inside a WHERE clause you can use {Desc[de]} to match
exactly one language or {Desc[ANY]} to match any language
• Parameters are passed using the question mark, where {date} > ?startDate
• Outer join parameter, it is used to include matches with missing rows
inside the localized table (xxxxxLP), for example :
1 SELECT {p:PK}
2 FROM {Product AS p}
3 WHERE {p:description[en]:o} LIKE '%text%'
4 OR {p:description[de]:o} LIKE '%text%'

If you use ! after a type SAP Hybris won’t load any sub types, for
example from {product!} will load only Product type items.

Examples
All Users
1 select * from {User}

Category by catalog version


1 select {c:pk} from {Category as c} where{c:catalogVersion}=?
catalogVersion

All Users ordered by desc name


1 select {name[en]} from {User} order by {name} DESC

Select distinct products


1 select distinct {name[en]} from {Product} order by {name[en]} asc

Select products and order them by price


1 select distinct {prd.name[en]},{price.price} from {Product as prd
join PriceRow as price on {prd:code} = {price:productId}} order
by {price.price} asc
Select all products with an online date past 1st January
1 select {name[en]}, {OnlineDate} from {Product} where {code} in ( {{
select {code} from {Product} where {OnlineDate} > '2016-01-01
00:00:00.0' }} )

You can test all flexible search queries directly from the HAC

Flexible Search Service


1 package de.hybris.platform.servicelayer.search;
2

3 import de.hybris.platform.core.model.ItemModel;
4 import de.hybris.platform.servicelayer.search.FlexibleSearchQuery;
5 import de.hybris.platform.servicelayer.search.RelationQuery;
6 import de.hybris.platform.servicelayer.search.SearchResult;
7 import de.hybris.platform.servicelayer.search.TranslationResult;
8 import java.util.List;
9 import java.util.Map;
10

11

12 public interface FlexibleSearchService


13 {
14 <T> T getModelByExample(T arg0);
15 <T> List<T> getModelsByExample(T arg0);
16 <T> SearchResult<T> search(FlexibleSearchQuery arg0);
17 <T> SearchResult<T> search(String arg0);
18 <T> SearchResult<T> search(String arg0, Map<String, ? extends
Object> arg1);
19 <T> SearchResult<T> searchRelation(ItemModel arg0, String arg1,
int arg2, int arg3);
20 <T> SearchResult<T> searchRelation(RelationQuery arg0);
21 <T> T searchUnique(FlexibleSearchQuery arg0);
22 TranslationResult translate(FlexibleSearchQuery arg0);
23 }

Create a Flexible Search query


1 import de.hybris.platform.servicelayer.search.FlexibleSearchService
2 import de.hybris.platform.servicelayer.search.FlexibleSearchQuery
3 import de.hybris.platform.servicelayer.search.SearchResult
4 import de.hybris.platform.core.model.product.ProductModel
5

6 FlexibleSearchService fsqs = spring.getBean("flexibleSearchService")


7
8 String q = "select {code[en]} from {Product} where {code[ANY]} like ?
code"
9 FlexibleSearchQuery myFlexibleSearchQuery = new FlexibleSearchQuery(q
)
10 myFlexibleSearchQuery.addQueryParameter('code', '109%')
11

12 SearchResult result = fsqs.<ProductModel>search(myFlexibleSearchQuery


)
13

14 println result.getTotalCount()

This would print 4 on my system.

Product Variants & Category Variants

Product Variants
When you work with products you often need to model variants, a variant
represent a variation of a base product. It has attributes from the base
product, and defines its own variation attributes. For example let’s define
laptops, they are Products with specific attributes like the screen size and
variants with specific attributes like the disk capacity.
1 <enumtypes>
2 <enumtype code="ScreenSize">
3 <value code="THIRTEEN" />
4 <value code="FOURTEEN" />
5 <value code="FIFTEEN" />
6 </enumtype>
7 </enumtypes>
8
9 <itemtypes>
10 <itemtype code="Laptop" extends="Product" autocreate="true"
generate="true">
11 <attributes>
12 <attribute qualifier="ScreenSize" type="ScreenSize">
13 <persistence type="property" />
14 </attribute>
15 </attributes>
16 </itemtype>
17
18 <itemtype code="LaptopVariant" extends="VariantProduct"
autocreate="true" generate="true"
19 jaloclass="com.hybhub.jalo.Car">
20 <attributes>
21 <attribute qualifier="diskCapacity" type="int" metatype="
VariantAttributeDescriptor">
22 <persistence type="property"/>
23 </attribute>
24 </attributes>
25 </itemtype>
26 </itemtypes>

To mark an attribute as a variant descriptor, you need to use


metatype=“VariantAttributeDescriptor”
This has on major downside, you won’t be able to access the screen size attribute
from your product variant ! Why, because variant product has a direct line of
inheritance to Product and our screen size attribute is defined in the laptop
subtype.
You are probably thinking that you could simply move the screen size attribute
into the laptop variant item.
1 <itemtype code="LaptopVariant" extends="VariantProduct" autocreate="
true" generate="true"
2 jaloclass="com.hybhub.jalo.Car">
3 <attributes>
4 <attribute qualifier="diskCapacity" type="int" metatype="
VariantAttributeDescriptor">
5 <persistence type="property"/>
6 </attribute>
7 <attribute qualifier="ScreenSize" type="ScreenSize">
8 <persistence type="property" />
9 </attribute>
10 </attributes>
11 </itemtype>

This is a bad idea, since it is described on the variant level, you need to define
a screen size for all your variants, even if they all have the same.
Why not defining the screen size directly on the product type ? well it’s also a
bad design since you might have products that are not laptops !
Diagram showing what the problem with product variant is:
Category Variants
A different approach is to build category variants with specific attributes. For
example our laptop category has a screen size attribute:
1 <itemtype code="LaptopCategory" extends="VariantValueCategory">
2 <attributes>
3 <attribute qualifier="ScreenSize" type="ScreenSize">
4 <persistence type="property" />
5 </attribute>
6 </attributes>
7 </itemtype>
8
9 <itemtype code="LaptopVariant" extends="VariantProduct" autocreate="
true" generate="true">
10 <attributes>
11 <attribute qualifier="diskCapacity" type="int" metatype="
VariantAttributeDescriptor">
12 <persistence type="property"/>
13 </attribute>
14 </attributes>
15 </itemtype>

How to create a new product : You cannot create your first


VariantCategory from an impex unless you skip the service layer
VariantValueCategoryValidateInterceptor. You could also manually
create one from the HMC and then use it as the super category
1 $productCatalog=electronicsProductCatalog
2 $productCatalogName=Electronics Product Catalog
3 $catalogVersion=catalogversion(catalog(id[default=$productCatalog]),
version[default='Staged'])[unique=true,default=$productCatalog:
Staged]
4 $supercategories=supercategories(code, $catalogVersion)
5 $baseProduct=baseProduct(code,$catalogVersion)
6 $approved=approvalstatus(code)[default='check']
7
8 # Insert Categories
9 INSERT_UPDATE LaptopCategory;code[unique=true];name[lang=en];
ScreenSize(code);$supercategories;$catalogVersion
10 ;000100;Laptop;THIRTEEN;1
11 ;000101;Laptop;FIFTEEN;1
12
13 INSERT_UPDATE Product;code[unique=true];$supercategories;
manufacturerName;manufacturerAID;unit(code);variantType(code);
$catalogVersion;$approved
14 ;000010;000100;Apple;MBP-13;pieces;LaptopVariant
15 ;000011;000100;Apple;MBP-15;pieces;LaptopVariant
16
17 INSERT_UPDATE LaptopVariant;code[unique=true];$baseProduct;unit(code)
;diskCapacity;approvalstatus(code)[default='approved'];
$catalogVersion
18 ;000100_256;000010;pieces;256;
19 ;000100_512;000010;pieces;512;
20 ;000101_256;000011;pieces;256;
21 ;000101_512;000011;pieces;512;

We now have a base laptop which holds the screen size through the category
variant, and a variant attribute disk capacity. We did all this without changing
the product model !
The downside of this is that the value of the screen size is held by
the category and not the product.

Classification attributes

SAP Hybris give you the possibility to classify your product, what is the
difference between classification and categorization ?
• You can categorize your laptop with : Electronic -> Computer -> Laptop.
• You can classify your laptop with its color, its screen size, its disk
capacity…
The difference is that categorization is vertical while classification is horizontal.
For example to classify our laptop :
1 $productCatalog=electronicsProductCatalog
2 $productCatalogName=Electronics Product Catalog
3 $catalogVersion=catalogversion(catalog(id[default=$productCatalog]),
version[default='Staged'])[unique=true,default=$productCatalog:
Staged]
4 $classCatalogVersion=catalogversion(catalog(id[default='
ElectronicsClassification']),version[default='1.0'])[unique=true,
default='ElectronicsClassification:1.0']
5 $classSystemVersion=systemVersion(catalog(id[default='
ElectronicsClassification']),version[default='1.0'])[unique=true]
6 $class=classificationClass(ClassificationClass.code,
$classCatalogVersion)[unique=true]
7 $supercategories=supercategories(code, $catalogVersion)
8 $supercategoriesRel=source(code, $classCatalogVersion)[unique=true]
9 $categories=target(code, $catalogVersion)[unique=true]
10 $attribute=classificationAttribute(code,$classSystemVersion)[unique=
true]
11 $unit=unit(code,$classSystemVersion)
12 $approved=approvalstatus(code)[default='check']
13 $baseProduct=baseProduct(code,$catalogVersion)
14 $clAttrModifiers=system='ElectronicsClassification',version='1.0',
translator=de.hybris.platform.catalog.jalo.classification.impex.
ClassificationAttributeTranslator,lang=en
15
16 # Insert Classifications
17 INSERT_UPDATE ClassificationClass;$classCatalogVersion;code[unique=
true];name[lang=en];allowedPrincipals(uid)[default='customergroup
']
18 ;;2002;Laptop
19
20 # Insert Classification Attributes
21 INSERT_UPDATE ClassificationAttribute;$classSystemVersion;code[unique
=true];name[lang=en]
22 ;;screen size;Screen Size
23
24 INSERT_UPDATE ClassAttributeAssignment;$class;$attribute;position;
$unit;attributeType(code[default=string]);multiValued[default=
false];range[default=false];localized[default=false]
25 ;2002;screen size;1;16;number;false;false
26
27 INSERT_UPDATE CategoryCategoryRelation;$categories;
$supercategoriesRel
28 ;1;2002
29
30 $feature1=@screen size[$clAttrModifiers];
31 INSERT_UPDATE Product;code[unique=true];$supercategories;
manufacturerName;manufacturerAID;unit(code);variantType(code);
$feature1;$catalogVersion;$approved
32 ;000010;1;Apple;MBP-13;pieces;LaptopVariant;13
33 ;000011;1;Apple;MBP-15;pieces;LaptopVariant;15
34
35 INSERT_UPDATE LaptopVariant;code[unique=true];$baseProduct;unit(code)
;diskCapacity;approvalstatus(code)[default='approved'];
$catalogVersion
36 ;000100_256;000010;pieces;256;
37 ;000100_512;000010;pieces;512;
38 ;000101_256;000011;pieces;256;
39 ;000101_512;000011;pieces;512;

The same product could be classified from two different classification tree ! It
offers a lot of flexibility and it can be modified without changing the SAP Hybris
model type !
Chapter 5

Order management

Through this chapter you will learn how to work with orders within an SAP
Hybris e-commerce system.

Business process
SAP Hybris has out of the box a process engine (yacceleratorfulfilmentprocess
extension). Business processes help you to define a list of actions that depend on
each other, and terminate with a status that will decide the action that would
follow. For example the first steps of the order-process.xml business process :

88
Let’s create our own business process, we won’t do anything just having few
actions, first we need to define our business process :
1 <itemtype code="MyProcess" autocreate="true" generate="true" extends=
"BusinessProcess">
2 <attributes>
3 <attribute qualifier="fail" type="boolean">
4 <persistence type="property" />
5 </attribute>
6 <attribute qualifier="error" type="boolean">
7 <persistence type="property" />
8 </attribute>
9 </attributes>
10 </itemtype>

You know need to define your process, create a new file named
myprocess-process.xml under /resources/hybhubaddon/process/, my extension
is hybhubaddon :
1 <?xml version="1.0" encoding="utf-8"?>
2 <process xmlns="http://www.hybris.de/xsd/processdefinition" start="
firstStep" name="myProcess" processClass="com.hybhub.hybhubaddon.
model.MyProcessModel">
3
4 <action id="firstStep" bean="firstStepAction">
5 <transition name="OK" to="secondStep"/>
6 <transition name="NOK" to="abortStep"/>
7 </action>
8
9 <action id="secondStep" bean="secondStepAction">
10 <transition name="OK" to="success"/>
11 <transition name="NOK" to="error"/>
12 </action>
13
14 <action id="abortStep" bean="abortStepAction">
15 <transition name="OK" to="failed"/>
16 </action>
17
18 <end id="error" state="ERROR">All went wrong.</end>
19 <end id="failed" state="FAILED">Couldn't run the process.</end>
20 <end id="success" state="SUCCEEDED">All good.</end>
21
22 </process>

There are 4 several types of nodes:


• Wait nodes wait for a subprocess or an external process result
• Notify nodes inform a user or user group of the state of a process
• Action nodes carry out process logic and permit alternative actions to be
carried out
• End nodes end the process and store state in a process item
First step, will decide what to do based on the fail flag
1 package com.hybhub.hybhubaddon.actions.myprocess;
2

3 import de.hybris.platform.processengine.action.
AbstractSimpleDecisionAction;
4 import de.hybris.platform.task.RetryLaterException;
5

6 import com.hybhub.hybhubaddon.model.MyProcessModel;
7

9 public class FirstStepAction extends AbstractSimpleDecisionAction<


MyProcessModel>
10 {
11 @Override
12 public Transition executeAction(final MyProcessModel myProcess)
throws RetryLaterException, Exception
13 {
14 if (myProcess.isFail())
15 {
16 return Transition.NOK;
17 }
18

19 return Transition.OK;
20 }
21 }

Second step, will return success or error based on the error flag
1 package com.hybhub.hybhubaddon.actions.myprocess;
2

3 import de.hybris.platform.processengine.action.
AbstractSimpleDecisionAction;
4 import de.hybris.platform.task.RetryLaterException;
5

6 import com.hybhub.hybhubaddon.model.MyProcessModel;
7

9 public class SecondStepAction extends AbstractSimpleDecisionAction<


MyProcessModel>
10 {
11 @Override
12 public Transition executeAction(final MyProcessModel myProcess)
throws RetryLaterException, Exception
13 {
14 if (myProcess.isError())
15 {
16 return Transition.NOK;
17 }
18 return Transition.OK;
19 }
20 }

Abort step will log something and return OK


1 package com.hybhub.hybhubaddon.actions.myprocess;
2

3 import de.hybris.platform.processengine.action.
AbstractSimpleDecisionAction;
4 import de.hybris.platform.task.RetryLaterException;
5

6 import org.apache.log4j.Logger;
7

8 import com.hybhub.hybhubaddon.model.MyProcessModel;
9

10

11 public class AbortStepAction extends AbstractSimpleDecisionAction<


MyProcessModel>
12 {
13 private final static Logger LOG = Logger.getLogger(
AbortStepAction.class);
14

15 @Override
16 public Transition executeAction(final MyProcessModel myProcess)
throws RetryLaterException, Exception
17 {
18 LOG.error("The process " + myProcess.getCode() + " failed !")
;
19 return Transition.OK;
20 }
21 }

Now we need to wire them all using Spring xml configuration :


1 <bean id="myProcess" class="de.hybris.platform.processengine.
definition.ProcessDefinitionResource" >
2 <property name="resource" value="classpath:/hybhubaddon/process/
myprocess-process.xml"/>
3 </bean>
4
5 <bean id="firstStepAction" class="com.hybhub.hybhubaddon.actions.
myprocess.FirstStepAction" parent="abstractAction" />
6 <bean id="secondStepAction" class="com.hybhub.hybhubaddon.actions.
myprocess.SecondStepAction" parent="abstractAction" />
7 <bean id="abortStepAction" class="com.hybhub.hybhubaddon.actions.
myprocess.AbortStepAction" parent="abstractAction" />

Let’s test our new business process using a Groovy script :


1 import com.hybhub.hybhubaddon.model.MyProcessModel
2 import de.hybris.platform.servicelayer.model.ModelService
3 import de.hybris.platform.processengine.BusinessProcessService
4

5 ModelService modelService = spring.getBean("modelService")


6 BusinessProcessService bpService = spring.getBean("
businessProcessService")
7

8 MyProcessModel myprocess = bpService.createProcess("myProcess" +


9 System.currentTimeMillis(), "myProcess
")
10 myprocess.setFail(true)
11 myprocess.setError(true)
12

13 modelService.save(myprocess)
14 bpService.startProcess(myprocess)
15

16 modelService.refresh(myprocess)
17 println myprocess.state

You can play around with the two flags and check the result on the HMC, you
can see the process state, and the log for each steps.

Fulfillment process
In this chapter we study the order fulfillment process, this process is triggered
when the customer triggers the place order action, then SAP Hybris will execute
a set of actions to fulfill the order.
Here is the list of all possible transitions for the order fulfillment process :
1. Check order, verify required data
2. Check authorize payment, check that the current order has a payment info
attached
3. Reserve amount, change the status of the order to
PAYMENT_AMOUNT_RESERVED
4. Send payment failed notification, publish an event for the failed
authorization
5. Check transaction review status, check that the transaction has been
authorized
6. Fraud check, check couple of criteria to detect potential fraud (excessive
amount, black listed customer,….)
7. Notify customer about fraud, contact the customer about the fraudulent
order
8. Manual order check CSA, prepare the order to be manually check by a
customer agent
9. Order manual checked, take the decision to follow or not the fulfillment
process after the manual check
10. Schedule for cleanUp, try to cleanup a fraudulent or failed order
11. Cancel order
12. Send order placed notification, send a notification to the customer after
his order has been successfully placed
13. Take payment action, capture the payment
14. Send payment failed notification, send a message to the customer after a
failed capture attempt
15. Split order, try to split the order in multiple consignment
16. Is process completed, watch for the waitForWarehouseSubprocessEnd to
end before moving on with the fulfillment
17. Send order completed notification, order has been shipped and is a success
you can find the order fulfillment process under
/yacceleratorfulfilmentprocess/resources/yacceleratorfulfilmentprocess/process/order-
process.xml

Shopping cart handling


First it’s important to understand that Carts and Orders both extend Abstract
Orders, they contain equivalent date but a cart is a temporary and volatile
object created when a customer is shopping online, when the session times out
and when the clean cart job is processed carts are discarded. Orders are created
from carts but they are persistent once they have been placed by a customer.
It’s important to understand that orders are created by making a
copy of the cart, they are different objects within SAP Hybris, even
the order entries are copied.
1. A customer access the store front, Hybris will create a new session, at that
point no carts have been created yet.
2. The customer adds a product.
1. The cart service (cartService) will try to load the cart from the
session, in our case the customer has not cart yet, so the cart
factory (cartFactory) will handle the cart creation (generate a code,
add user, add currency, set the date). It could be a standard
persisted cart or a in memory cart (not persisted), for this you need
to configure default.session.cart.type (Cart, InMemoryCart or your
own implementation).
2. The commerce add to cart strategy (CommerceAddToCartStrategy)
will add a new entry into the cart entry collection, then it will mark
the cart as not calculated.
3. The calculation service (CalculationService) will calculate the total
price of the cart.
3. Before the checkout process, the customer will log-in or create a new
account (guest account for example), during this log-in phase the cart
will be attached to the customer account.
4. During the checkout process the customer will add or select a delivery
address, attach a payment info….
5. When the Customer places the order, the order is created by making a
copy of the cart (order entries as well).
Checkout flow
SAP Hybris gives you the possibility to configure the entire checkout flow
independently for each store (since V5.2). All configuration is done using
Spring beans and interface implementation.
SAP Hybris checkout is configured with :
1. Checkout steps, they hold information about the next, previous and
current link, about the validator to use (oftenly the controller is marked
with a PreValidateStep annotation).
2. A validate result maps, based on the different validation success or fail
the checkout flow will oftenly need to redirect the process to a given step,
to hold the different redirection the checkout group has a string map with
entry like REDIRECT_TO_DELIVERY_ADDRESS that would point to
a spring MVC redirection redirect:/checkout/multi/delivery-address/add
3. The checkout flow progress bar, it is a map with each step ordered by the
number in which they are populated under the progress bar
To create a new checkout flow you need to create a new bean from the class
de.hybris.platform.acceleratorstorefrontcommons.checkout.steps.CheckoutGroup,
this is an example of the out of the box checkout flow configured with an extra
step. Since multiple checkout flows can live under the same system instead of
updating the existing flow we declare a new one named
defaultHybhubCheckoutGroup with a alias hybhubCheckoutGroup :
1 <bean id="REDIRECT_TO_HYBHUB" class="java.lang.String">
2 <constructor-arg value="redirect:/checkout/multi/hybhub"/>
3 </bean>
4
5 <alias name="defaultHybhubCheckoutGroup" alias="hybhubCheckoutGroup"
/>
6 <bean id="defaultHybhubCheckoutGroup" class="de.hybris.platform.
acceleratorstorefrontcommons.checkout.steps.CheckoutGroup">
7 <property name="groupId" value="hybhubCheckoutGroup"/>
8 <property name="checkoutStepMap">
9 <map merge="true">
10 <entry key="multi" value-ref="hybhubMultiStepCheckout"/>
11 <entry key="hybhub" value-ref="hybhubStep"/>
12 <entry key="delivery-address" value-ref="
hybhubDeliveryAddressCheckoutStep"/>
13 <entry key="delivery-method" value-ref="
deliveryMethodCheckoutStep"/>
14 <entry key="pickup-location" value-ref="
pickupLocationCheckoutStep"/>
15 <entry key="payment-method" value-ref="
paymentMethodCheckoutStep"/>
16 <entry key="summary" value-ref="summaryCheckoutStep"/>
17 </map>
18 </property>
19 <property name="validationResultsMap">
20 <map merge="true">
21 <entry key="FAILED" value-ref="REDIRECT_TO_CART"/>
22 <entry key="REDIRECT_TO_DELIVERY_ADDRESS" value-ref="
REDIRECT_TO_DELIVERY_ADDRESS"/>
23 <entry key="REDIRECT_TO_PICKUP_LOCATION" value-ref="
REDIRECT_TO_PICKUP_LOCATION"/>
24 <entry key="REDIRECT_TO_CART" value-ref="REDIRECT_TO_CART
"/>
25 <entry key="REDIRECT_TO_PAYMENT_METHOD" value-ref="
REDIRECT_TO_PAYMENT_METHOD"/>
26 <entry key="REDIRECT_TO_DELIVERY_METHOD" value-ref="
REDIRECT_TO_DELIVERY_METHOD"/>
27 </map>
28 </property>
29 <property name="checkoutProgressBar">
30 <map merge="true">
31 <entry key="1" value-ref="hybhubStep"/>
32 <entry key="2" value-ref="deliveryAddressCheckoutStep"/>
33 <entry key="3" value-ref="deliveryMethodCheckoutStep"/>
34 <entry key="4" value-ref="paymentMethodCheckoutStep"/>
35 <entry key="5" value-ref="defaultSummaryCheckoutStep"/>
36 </map>
37 </property>
38 </bean>

Out of the box Hybris already has those steps :


• deliveryMethodCheckoutStep
• pickupLocationCheckoutStep
• paymentMethodCheckoutStep
• summaryCheckoutStep
It also has multiStepCheckout and deliveryAddressCheckoutStep but we need to
update their transitions so we declare new beans, here are the 3 steps we need :
1 <alias name="defaultHybhubStep" alias="hybhubStep" />
2 <bean id="defaultHybhubStep" parent="checkoutStep">
3 <property name="checkoutGroup" ref="hybhubCheckoutGroup"/>
4 <property name="checkoutStepValidator" ref="hybhubValidator"/>
5 <property name="transitions">
6 <map merge="true">
7 <entry key="previous" value-ref="
REDIRECT_MULTI_STEP_CHECKOUT"/>
8 <entry key="current" value-ref="REDIRECT_TO_HYBHUB"/>
9 <entry key="next" value-ref="REDIRECT_TO_DELIVERY_ADDRESS
"/>
10 </map>
11 </property>
12 <property name="progressBarId" value="hybhubStep"/>
13 </bean>
14
15 <alias name="defaultHybhubMultiStepCheckout" alias="
hybhubMultiStepCheckout" />
16 <bean id="defaultHybhubMultiStepCheckout" parent="checkoutStep">
17 <property name="checkoutGroup" ref="hybhubCheckoutGroup"/>
18 <property name="checkoutStepValidator" ref="
defaultResponsiveMultiStepCheckoutValidator"/>
19 <property name="transitions">
20 <map>
21 <entry key="previous" value-ref="REDIRECT_TO_CART"/>
22 <entry key="current" value-ref="
REDIRECT_MULTI_STEP_CHECKOUT"/>
23 <entry key="next" value-ref="REDIRECT_TO_HYBHUB"/>
24 </map>
25 </property>
26 <property name="progressBarId" value="multi"/>
27 </bean>
28
29 <alias name="defaultHybhubDeliveryAddressCheckoutStep" alias="
hybhubDeliveryAddressCheckoutStep" />
30 <bean id="defaultHybhubDeliveryAddressCheckoutStep" parent="
checkoutStep">
31 <property name="checkoutGroup" ref="hybhubCheckoutGroup"/>
32 <property name="checkoutStepValidator" ref="
defaultResponsiveDeliveryAddressCheckoutValidator"/>
33 <property name="transitions">
34 <map merge="true">
35 <entry key="previous" value-ref="REDIRECT_TO_HYBHUB"/>
36 <entry key="current" value-ref="
REDIRECT_TO_DELIVERY_ADDRESS"/>
37 <entry key="next" value-ref="REDIRECT_TO_DELIVERY_METHOD"
/>
38 </map>
39 </property>
40 <property name="progressBarId" value="deliveryAddress"/>
41 </bean>

You may have noticed that our Hybhub step is validated by hybhubValidator,
it’s an implementation of de.hybris.platform.acceleratorstorefrontcommons.
checkout.steps.validation.AbstractCheckoutStepValidator which let you validate
on enter and on exit the step controller, here is our implementation for the
hybhub step:
1 package com.hybhub.storefront.checkout.steps.validation.impl;
2

3 import de.hybris.platform.acceleratorstorefrontcommons.checkout.steps
.validation.AbstractCheckoutStepValidator;
4 import de.hybris.platform.acceleratorstorefrontcommons.checkout.steps
.validation.ValidationResults;
5 import de.hybris.platform.commercefacades.order.data.CartData;
6

7 import org.apache.log4j.Logger;
8 import org.springframework.web.servlet.mvc.support.RedirectAttributes
;
9

10

11 public class DefaultHybhubValidator extends


AbstractCheckoutStepValidator
12 {
13

14 final static Logger LOG = Logger.getLogger(DefaultHybhubValidator


.class);
15

16 @Override
17 public ValidationResults validateOnEnter(final RedirectAttributes
redirectAttributes)
18 {
19 final CartData cartData = getCheckoutFacade().getCheckoutCart
();
20 LOG.info("Validating on enter with Hybhub Validator cart : "
+ cartData.getCode());
21 return ValidationResults.SUCCESS;
22 }
23

24 @Override
25 public ValidationResults validateOnExit()
26 {
27 final CartData cartData = getCheckoutFacade().getCheckoutCart
();
28 LOG.info("Validating on exit with Hybhub Validator cart : " +
cartData.getCode());
29 return ValidationResults.SUCCESS;
30 }
31 }

We now need to implement a controller to handle our step :


1 package com.hybhub.storefront.controllers.pages.checkout.steps;
2

3 import de.hybris.platform.acceleratorstorefrontcommons.annotations.
PreValidateCheckoutStep;
4 import de.hybris.platform.acceleratorstorefrontcommons.annotations.
RequireHardLogIn;
5 import de.hybris.platform.acceleratorstorefrontcommons.checkout.steps
.CheckoutStep;
6 import de.hybris.platform.acceleratorstorefrontcommons.constants.
WebConstants;
7 import de.hybris.platform.acceleratorstorefrontcommons.controllers.
pages.checkout.steps.AbstractCheckoutStepController;
8 import de.hybris.platform.cms2.exceptions.CMSItemNotFoundException;
9

10 import org.springframework.stereotype.Controller;
11 import org.springframework.ui.Model;
12 import org.springframework.web.bind.annotation.RequestMapping;
13 import org.springframework.web.bind.annotation.RequestMethod;
14 import org.springframework.web.servlet.mvc.support.RedirectAttributes
;
15

16

17 @Controller
18 @RequestMapping(value = "/checkout/multi/hybhub")
19 public class HybhubStepController extends
AbstractCheckoutStepController
20 {
21 private static final String HYBHUB = "hybhub";
22

23 @RequestMapping(method = RequestMethod.GET)
24 @RequireHardLogIn
25 @Override
26 @PreValidateCheckoutStep(checkoutStep = HYBHUB)
27 public String enterStep(final Model model, final
RedirectAttributes redirectAttributes) throws
CMSItemNotFoundException
28 {
29

30 this.prepareDataForPage(model);
31 storeCmsPageInModel(model, getContentPageForLabelOrId(HYBHUB)
);
32 setUpMetaDataForContentPage(model, getContentPageForLabelOrId
(HYBHUB));
33 model.addAttribute(WebConstants.BREADCRUMBS_KEY,
34 getResourceBreadcrumbBuilder().getBreadcrumbs("
checkout.multi.deliveryMethod.breadcrumb"));
35 model.addAttribute("metaRobots", "noindex,nofollow");
36 setCheckoutStepLinksForModel(model, getCheckoutStep());
37

38 return "pages/checkout/multi/hybhubPage";
39 }
40

41 @RequestMapping(value = "/back", method = RequestMethod.GET)


42 @RequireHardLogIn
43 @Override
44 public String back(final RedirectAttributes redirectAttributes)
45 {
46 return getCheckoutStep().previousStep();
47 }
48

49 @RequestMapping(value = "/next", method = RequestMethod.GET)


50 @RequireHardLogIn
51 @Override
52 public String next(final RedirectAttributes redirectAttributes)
53 {
54 return getCheckoutStep().nextStep();
55 }
56

57 protected CheckoutStep getCheckoutStep()


58 {
59 return getCheckoutStep(HYBHUB);
60 }
61 }

To handle the view you need to create pages/checkout/multi/hybhubPage.jsp :


1 <%@ page trimDirectiveWhitespaces="true"%>
2 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
3 <%@ taglib prefix="template" tagdir="/WEB-INF/tags/responsive/
template"%>
4 <%@ taglib prefix="cms" uri="http://hybris.com/tld/cmstags"%>
5 <%@ taglib prefix="spring" uri="http://www.springframework.org/tags
"%>
6 <%@ taglib prefix="form" uri="http://www.springframework.org/tags/
form"%>
7 <%@ taglib prefix="formElement" tagdir="/WEB-INF/tags/responsive/
formElement" %>
8 <%@ taglib prefix="multi-checkout" tagdir="/WEB-INF/tags/responsive/
checkout/multi"%>
9 <%@ taglib prefix="ycommerce" uri="http://hybris.com/tld/
ycommercetags" %>
10
11 <template:page pageTitle="${pageTitle}" hideHeaderLinks="true">
12
13 <div class="row">
14 <div class="col-sm-6">
15 <div class="checkout-headline">
16 <span class="glyphicon glyphicon-lock"></span>
17 <spring:theme code="checkout.multi.secure.checkout" text
="Secure Checkout"></spring:theme>
18 </div>
19 <multi-checkout:checkoutSteps checkoutSteps="${checkoutSteps
}" progressBarId="hybhubStep">
20 <jsp:body>
21 <ycommerce:testId code="hybhub">
22 <a href='<spring:url value="${nextStepUrl}"/>'
type="button" class="btn btn-primary btn-
block checkout-next"><spring:theme code="
checkout.multi.hybhub.continue" text="Next
"/></a>
23 </ycommerce:testId>
24 </jsp:body>
25 </multi-checkout:checkoutSteps>
26 </div>
27 <div class="col-sm-6 hidden-xs">
28 <h1>This is the Hybhub step</h1>
29 </div>
30 </div>
31
32 </template:page>

Finally you need to create a new page, we choose the


MultiStepCheckoutSummaryPageTemplate to make our life easier but it could
be another template :
1 $contentCatalog=electronicsContentCatalog
2 $contentCV=catalogVersion(CatalogVersion.catalog(Catalog.id[default=
$contentCatalog]),CatalogVersion.version[default=Staged])[default
=$contentCatalog:Staged]
3
4 INSERT_UPDATE ContentPage;$contentCV[unique=true];uid[unique=true];
name;masterTemplate(uid,$contentCV);label;defaultPage[default='
true'];approvalStatus(code)[default='approved'];homepage[default
='false'];
5 ;;hybhub;Hybhub Page;MultiStepCheckoutSummaryPageTemplate;hybhub

Don’t forget to run a synchronization or to change the catalog to the


Online one, otherwise you won’t be able to see the hybhub page !
Now you need to change the checkout flow group of your store, you can do it
from the HMC or from an impex query :
1 INSERT_UPDATE BaseStore;uid[unique=true];checkoutFlowGroup;
2 ;electronics;hybhubCheckoutGroup;

Go to the store front, and checkout your cart, you should now see your new step
!
ASM
SAP Hybris provides an Assister Service Module, it gives the customer service
employees the ability to assist customers in real time using the same interface
that the end customer ; the store front. The ASM module is compatible with
all SAP Hybris accelerator store front (B2C, B2B and Telco).
In order to install the ASM module you need to add the asm extensions into
your localextensions.xml file :
1 <extension name="assistedservicefacades"/>
2 <extension name="assistedservicestorefront"/>

You also need to install the assistedservicestorefront addon into your store front
extension, here my store front is named hybhubstorefront remember to use your
store front name, from SAP Hybris platform/bin folder run :
1 ant addoninstall -Daddonnames="assistedservicestorefront" -
DaddonStorefront.yacceleratorstorefront="hybhubstorefront"

Now start your server and run a system update (with assistedservicefacades
and assistedservicestorefront selected), when it’s finished access your store
front with this URL parameter asm=true, for example to access my electronic
store front on my localhost for development I use :
http://localhost:9001/hybhubstorefront/?site=electronics&asm=true.
The default user login / password is asagent / 123456**
You should see this :

You need to remember that from the ASM perspective you can:
• Find a customer’s account and session or an anonymous cart
• Map an anonymous cart to an existing customer
• Help a customer to create a new account
• Support a customer during add to cart and checkout flow processes
• Help a customer to manage his/her account

CS Cocpkit
SAP Hybris provides a Customer Service Cockpit, it uses the cockpit framework
(and not the next generation cockpit framework), this cockpit is loaded from the
cscockpit cockpit extension and available from : http://localhost:9001/cscockpit/.
It is meant to be used by operators in a call center environment for customer,
pre-sales and post sales operations.
You need to remember that from the customer service cockpit operators can :
• Manage customers (create or edit)
• Manage orders in behalf of a customer (create, cancel, update, refund,
return)
• Manage a customer’s cart
• Take payment
• Manage order’s delivery mode and address
• Manage subscription products
The current customer cockpit will probably be reimplemented by
SAP Hybris using the NG Cockpit framework
Chapter 6

Search & navigation

SAP Hybris provides a fast and customizable search and navigation with the
help of a Apache SOLR server (More information).

Solr index
A SOLR index is a fast text search database for products (or any other kind of
data), in order to use a SOLR index you need :
• A SolrServerConfig, which define the connections between SAP Hybris
and the Apache SOLR node(s)
– Standalone or Embedded (standalone is now the default and it’s the
preferred way of running SOLR as it’s how most systems in
production run)
– Embedded Master, to decide if only one SOLR server should take
care of all index operations
– Alive check interval, interval between check for a running system
– Connection timeout, timeout before SAP Hybris consider a
connection attempt a failure
– Socket timeout, timeout before SAP Hybris consider a socket access
a failure
– Total connections, total open connection to SOLR
– Total connections per host, total connections per SOLR host
– List of endpoints, representing all the SOLR server
– Use Master node exclusively for indexing, will force SAP Hybris to
access only non master nodes and to reserve master nodes for
indexing operations only
• one or more SolrEndpointUrl

107
– A url to access Apache solr (for example : http://solr.local:8983)
– A boolean to flag the node as a master
• A SolrIndexConfig, which defines the way SAP Hybris will index
documents within Apache SOLR
– Batch size, how many products SAP Hybris will index at the same
time, this configuration can have a lot of impact on the performances
– Number of threads, number of threads within SAP Hybris to handle
the indexing process
– Indexer mode, DIRECT means SAP Hybris will execute operation
on the running SOLR Index this means that the search result would
be inconsistent during the indexing operation this mode should be
used only during development, the TWO_PHASE mode will create
a new index where SAP Hybris will inject the new indexing result,
once the operation is done SAP Hybris will switch the active index
to be the one newly created
– Commit mode, Apache SOLR data are not reachable until you
commit them, there are different commit modes, never, after_index,
after_batch, and mixed
– Optimize mode, Apache SOLR can optimize its index by
defragmenting it, this operation could be resource expensive, you
can configure when it would be executed, never, after an index
operation or after a full index operation
– Errors handling, you can configure the behavior of the indexing
process when an error is raised
• A SolrSearchConfig
– Result page size
– Restrict field in response
– Include all facets in response
• A SolrIndexedType, defines the type of item to index and what attributes
– Composed type, the type of item to index
– A list of properties to index (More : Solr Indexed Property)
– A list of indexed queries (More : Solr Indexed Query)
– The default property value provider
– Model fields value provider
– Result converter
Solr Indexed Property

A Solr indexed type defines a list of properties from an item type that need to
be indexed, each of those properties are defined with :
• A name, this name will be used under the Solr index
• A type, the type of the attribute under the Solr index
• A sortable type
• A localized flag
• A currency flag
• A multi-value flag
• A used for spell checking flag
• A include in response flag
• A range and range sets
• A property value provider
• Value provider parameter(s)
• Category field flag
• Free text settings
• Facet settings
• Boost rules
Example, with the following customized product model :
1 <itemtype code="Product" autocreate="false" generate="false">
2 <attributes>
3 <attribute qualifier="exportToGoogleShopping" type="java.lang
.Boolean">
4 <persistence type="property" />
5 </attribute>
6 <attribute qualifier="lastCustomerReview" type="java.lang.
String">
7 <persistence type="property" />
8 </attribute>
9 </attributes>
10 </itemtype>

We will create 2 new properties for our product index, one facet property from
the exportToGoogleShopping and one free text search property from
lastCustomerReview :
exportToGoogleShopping facet :
1 INSERT_UPDATE SolrIndexedProperty;solrIndexedType(identifier)[unique=
true];name[unique=true];type(code);sortableType(code);currency[
default=false];localized[default=false];multiValue[default=false
];facet[default=true];facetType(code);facetSort(code);priority;
visible;useForSpellchecking[default=false];useForAutocomplete[
default=false];fieldValueProvider;valueProviderParameter;
facetDisplayNameProvider;customFacetSortProvider;
topValuesProvider;rangeSets(name)
2 ;electronicsProductType;exportToGoogleShopping;boolean;;;;false;;
MultiSelectAnd;;100;true;;;springELValueProvider;
getExportToGoogleShopping();;

lastCustomerReview free text search :


1 INSERT_UPDATE SolrIndexedProperty;solrIndexedType(identifier)[unique=
true];name[unique=true];type(code);sortableType(code);currency[
default=false];localized[default=false];multiValue[default=false
];facet[default=false];facetType(code);facetSort(code);priority;
visible;useForSpellchecking[default=false];useForAutocomplete[
default=false];fieldValueProvider;valueProviderParameter;ftsQuery
;ftsQueryBoost;ftsQueryMinTermLength;ftsWildcardQuery;
ftsWildcardQueryBoost;ftsWildcardQueryMinTermLength;
includeInResponse
2 ;electronicsProductType;lastCustomerReview;string;;;;;;;;100;true;;;
springELValueProvider;getLastCustomerReview();true;500;5;true
;100;10;false

In order to add a new free text attribute you need to configure the solr search
config with legacy mode to false, or to update the commerceSearchTextPopulator
bean and add your new field, in our case lastCustomerReview :
1 INSERT_UPDATE SolrSearchConfig;description[unique=true];pageSize;
legacyMode
2 ;electronicsPageSize;20;false

After running a full index job, and adding data both for
exportToGoogleShopping and lastCustomerReview look for products
from your store front, you should see the new facets and results
from the two attribute providers. Combinations are limitless

Implement your own value provider

The recommended way to create a new value provider is to create a new


implementation of the abstract class
de.hybris.platform.solrfacetsearch.provider.impl.AbstractValueResolver, the only
abstract method that you have to implement is addFieldValues, here is an
example of a simple value provider for our exportToGoogleShopping attribute :
1 package com.hybhub.hybhubaddon.search.solrfacetsearch.provider.impl;
2

3 import de.hybris.platform.core.model.product.ProductModel;
4 import de.hybris.platform.solrfacetsearch.config.IndexedProperty;
5 import de.hybris.platform.solrfacetsearch.config.exceptions.
FieldValueProviderException;
6 import de.hybris.platform.solrfacetsearch.indexer.IndexerBatchContext
;
7 import de.hybris.platform.solrfacetsearch.indexer.spi.InputDocument;
8 import de.hybris.platform.solrfacetsearch.provider.impl.
AbstractValueResolver;
9

10

11 public class ProductExportToGS extends AbstractValueResolver<


ProductModel, Object, Object>
12 {
13

14 @Override
15 protected void addFieldValues(final InputDocument inputDocument,
final IndexerBatchContext IndexerBatchContext,
16 final IndexedProperty indexedProperty, final ProductModel
productModel,
17 final ValueResolverContext<Object, Object>
valueResolverContext) throws
FieldValueProviderException
18 {
19 inputDocument.addField(indexedProperty,
20 productModel.getExportToGoogleShopping() == null ?
Boolean.FALSE : productModel.
getExportToGoogleShopping(),
21 valueResolverContext.getFieldQualifier());
22 }
23

24 }

We need to create a Spring bean for our value provider, it has to have
abstractValueResolver as a parent bean definition :
1 <bean id="productExportToGS" class="com.hybhub.hybhubaddon.search.
solrfacetsearch.provider.impl.ProductExportToGS"
2 parent="abstractValueResolver"/>

Build your platform and run the following impex query :


1 INSERT_UPDATE SolrIndexedProperty;solrIndexedType(identifier)[unique=
true];name[unique=true];type(code);sortableType(code);currency[
default=false];localized[default=false];multiValue[default=false
];facet[default=true];facetType(code);facetSort(code);priority;
visible;useForSpellchecking[default=false];useForAutocomplete[
default=false];fieldValueProvider;valueProviderParameter;
facetDisplayNameProvider;customFacetSortProvider;
topValuesProvider;rangeSets(name)
2 ;electronicsProductType;exportToGoogleShopping;boolean;;;;false;;
MultiSelectAnd;;100;true;;;productExportToGS;;;

Run a full indexation, you should now see that all products have a
exportToGoogleShopping facet, since we set it to Boolean.FALSE by default.

Solr Indexed Query

Indexer queries are used by the system to get the list of PKs it needs to work
on, there are different scenarios for the indexing process :
• Full query it runs a full indexation, SAP Hybris will get all products pks
from this query, by default it runs :**
1 SELECT {PK} FROM {Product}

Don’t forget that the query is executed by the anonymous user,


therefore the Frontend_ProductApprovalStatus search restriction
applies ({approvalStatus} = approved)
• Update query** it runs an update indexation on the existing SOLR index,
SAP Hybris will load the products that have been modified since the last
index time, therefore only products that have been modified (modifiedtime
attribute) since the last update (date is injected as an argument by the
indexing service) would be indexed
SELECT DISTINCT tbl.pk, tbl.code FROM ( {{ SELECT DISTINCT {
p:PK} AS pk, {p:code} AS code FROM {Product AS p LEFT JOIN
CustomerReview AS cr ON {cr:product}={p:PK} } WHERE {p:
varianttype} IS NULL AND ({p:modifiedtime} >= ?lastIndexTime OR {
cr:modifiedtime} >= ?lastIndexTime)}} UNION {{ SELECT {p:PK}
AS pk, {p:code} AS code FROM {Product AS p} WHERE {p:code} IN (
{{ SELECT DISTINCT {sl:productCode} FROM {
StockLevel AS sl} WHERE {sl:modifiedtime} >= ?lastIndexTime
}} ) }}) tbl ORDER BY tbl.code
Don’t forget that the query is executed by the anonymous user,
therefore the Frontend_ProductApprovalStatus search restriction
applies ({approvalStatus} = approved)
• Partial update query** this operation is similar to the update process but
you can select the field you want to update, this kind of operation unlike
the others can’t be launched from a wizard, you would need to create a
different job for this. Here is an example of how to create a ** item type :
INSERT_UPDATE SolrExtIndexerCronJob;code[unique=true];job(code)[
unique=true];sessionLanguage(isocode);sessionCurrency(isoCode);
indexedType(identifier)[unique=true];query;facetSearchConfig(name
);indexerOperation(code);sessionUser(uid);queryParameterProvider;
indexedProperties ;partialUpdate-fromImpex-cronJob;
solrExtIndexerJob;en;USD;Product_Product;set in solrIndexerQuery;
electronicsIndex;partial_update;anonymous;ParameterProvider;name
The indexedProperties attribute is a collection of String, you can list
here the attribute you want to update, this is where you configure
the partial** behavior, if you don’t configure any properties**
• Delete query** this deletes documents from the index, for example you
could select all products that are not authorized or have been discontinued

Solr Search Field

Indexing listeners

During the indexing process you can use listeners to intercept and customize
a piece of the indexing operation. Each listeners can implement three kind of
actions, before, after and afterError, SAP Hybris provides three kind of listeners
:
• de.hybris.platform.solrfacetsearch.indexer.IndexerListener, will be
executed around indexations
• de.hybris.platform.solrfacetsearch.indexer.IndexerBatchListener, will be
executed around batch executions
• de.hybris.platform.solrfacetsearch.indexer.IndexerQueryListener, will be
executed around query executions
First let’s create an Abstract class for our listeners :
1 package com.hybhub.hybhubaddon.search.solrfacetsearch.indexer.impl;
2

3 import org.springframework.beans.factory.annotation.Required;
4

5 public abstract class AbstractHybhubListener


6 {
7 private String name;
8

9 public String getName()


10 {
11 return name;
12 }
13

14 @Required
15 public void setName(final String name)
16 {
17 this.name = name;
18 }
19 }

Example how to implement an IndexerListener listener :


1 package com.hybhub.hybhubaddon.search.solrfacetsearch.indexer.impl;
2

3 import de.hybris.platform.solrfacetsearch.indexer.IndexerContext;
4 import de.hybris.platform.solrfacetsearch.indexer.IndexerListener;
5 import de.hybris.platform.solrfacetsearch.indexer.exceptions.
IndexerException;
6

7 import org.slf4j.Logger;
8 import org.slf4j.LoggerFactory;
9

10

11 public class HybhubIndexerListenerImpl extends AbstractHybhubListener


implements IndexerListener
12 {
13

14 private final Logger LOG = LoggerFactory.getLogger(


HybhubIndexerListenerImpl.class);
15

16 @Override
17 public void beforeIndex(final IndexerContext arg0) throws
IndexerException
18 {
19 LOG.info("Before Index : " + getName());
20 }
21

22 @Override
23 public void afterIndex(final IndexerContext arg0) throws
IndexerException
24 {
25 LOG.info("After Index : " + getName());
26 }
27

28 @Override
29 public void afterIndexError(final IndexerContext arg0) throws
IndexerException
30 {
31 LOG.info("After Index Error : " + getName());
32 }
33

34 }

Example how to declare a bean for the listener and configure it as global :
1 <bean id="globaltHybhubIndexerListener" class="com.hybhub.
hybhubaddon.search.solrfacetsearch.indexer.impl.
HybhubIndexerListenerImpl">
2 <property name="name" value="globaltHybhubIndexerListener" />
3 </bean>
4
5 <bean id="globaltHybhubIndexerListenerDefinition" parent="
solrListenerDefinition">
6 <property name="listener" ref="globaltHybhubIndexerListener"
/>
7 </bean>

Listeners are called based on their priority, from the highest to the lowest
(reversed order for the after method) :
• Global listeners first, ordered by their priority index (default is 100)
• Listeners configured in the Facet Search Config
• Listeners configured in the Indexed Type

Solr Facet

The difference between normal search and facet search is that when you do a
normal search you follow a determined path, like a category path, it is fixed and
you need to know all the details about your product. Quite the opposite with
a facet search when you don’t need to know anything about the product, you
narrow down the results by applying filters to the list of products. SAP Hybris
faceted search gives the customer the ability to navigate through a collection
of products using facets.A facet can be anything from colors, prices, weigh,
internal components, classified as, warranty time, available in store…
If you still don’t understand what this means go to any of the big online retailers
you know, and you will that when you search for a product you can enter its
name then you would see a list of facets (usually) on the left.
In order to create a new facet, you only need to declare a new
SolrIndexedProperty and flag it as a facet, we will update the existing
pickupAvailableFlag and make a facet from it :
1 INSERT_UPDATE SolrIndexedProperty;solrIndexedType(identifier)[unique=
true];name[unique=true];type(code);fieldValueProvider;facet;
facetType(code);priority;
2 ;electronicsProductType;pickupAvailableFlag;boolean;
productPickupAvailabilityValueProvider;true;MultiSelectAnd;50;
facetType could be :
• Refine, meaning that this would be the only facet used if selected
• MultiSelectAnd, it filters all search
• MultiSelectOr, it adds products based on the facet
After running a full SOLR indexation you should see the new facet under your
product search page.

Solr Facet Range

In order to have efficient facets in some cases you would need to create ranges,
the simplest example is for prices. Without ranges SAP Hybris would create
one facet perspective per price, that would be inefficient and resource consuming.
To achieve efficient facets you will need to create ranges.
The simplest way to understand is to have a look at the out of the box price
ranges available under SAP Hybris, in the example below we create different
ranges for prices in USD, from 0 to 50…For each facet we have a UI string to
display “$0-$49.99” for example, :
1 # Define price range set
2 INSERT_UPDATE SolrValueRangeSet;name[unique=true];qualifier;type;
solrValueRanges(&rangeValueRefID)
3 ;electronicsPriceRangeUSD;USD;double;rangeRefUSD1,rangeRefUSD2,
rangeRefUSD3,rangeRefUSD4,rangeRefUSD5
4
5 # Define price ranges
6 INSERT_UPDATE SolrValueRange;&rangeValueRefID;solrValueRangeSet(name)
[unique=true];name[unique=true];from;to
7 ;rangeRefUSD1;electronicsPriceRangeUSD; $0-$49.99; 0; 49.99
8 ;rangeRefUSD2;electronicsPriceRangeUSD; $50-$199.99; 50; 199.99
9 ;rangeRefUSD3;electronicsPriceRangeUSD; $200-$499.99; 200; 499.99
10 ;rangeRefUSD4;electronicsPriceRangeUSD; $500-$999.99; 500; 999.99
11 ;rangeRefUSD5;electronicsPriceRangeUSD;$1,000-$100,000;1000; 100000

When you create a SolrIndexedProperty you can specify rangeSets.

Auto suggestion & keywords & stopwords & synonyms

Auto suggestion

If a SOLR indexed property os configured to be auto complete its content become


available for a search from the Search Box Component.
To activate it from an indexed property execute the following impex query :
1 INSERT_UPDATE SolrIndexedProperty;solrIndexedType(identifier)[unique=
true];name[unique=true];useForAutocomplete
2 ;electronicsProductType;code;true

The Search box component is configurable :


• delay before auto complete
• maximum number of products
• minimum of characters before sending a query
• display images

Keywords

Keywords are configured within the solr facet search config, they provide you a
the ability to redirect the customer to a page for a given query, for example if
a customer enters the work cart under the search component you redirect him
or her to the cart page.
First you need a SolrFacetSearchKeywordRedirect, this would hold :
• the language
• the keyword
• match type (EXACT, START_WITH, ENDS_WITH, CONTAINS,
REGEX)
• ignore case flag
• a link to a facet search configuration
• a link to a redirect object (Abstract redirect) it can be :
– a category redirect
– a direct url
– a page redirect
– a product redirect
Example how to create a new redirect for a product :
1 $productCatalog=electronicsProductCatalog
2 $productCatalogVersion=catalogVersion(CatalogVersion.catalog(Catalog.
id[default=$productCatalog]),CatalogVersion.version[default=
Staged])[default=$productCatalog:Staged]
3 INSERT_UPDATE SolrProductRedirect;redirectItem(code,
$productCatalogVersion)[unique=true];&redirectRefID
4 ;726510;contentCatalogName-redirectRefID-726510
5
6 INSERT_UPDATE SolrFacetSearchKeywordRedirect;facetSearchConfig(name)[
unique=true];language(isocode)[unique=true];keyword[unique=true];
matchType(code)[unique=true];redirect(&redirectRefID);ignoreCase
7 ;electronicsIndex;en;"the best camera";EXACT;contentCatalogName-
redirectRefID-726510;true
Try a search using the best camera as a keyword.

Stopwords

Stopwords are words that SAP Hybris is ignoring during a search, because you
don’t want to search words like the or a, so a list needs to be created and
maintained for each language. Happily SAP Hybris and SOLR provide a
standard stopword list for most languages, you can find it under your config
folder config/solr/instances/default/
configsets/default/conf/lang/stopwords_en.txt (example with
stopwords for English, but other languages are available).
If you want to manage stopwords from SAP Hybris you could create them from
Impex queries :
1 INSERT_UPDATE SolrStopWord;facetSearchConfig(name)[unique=true];
language(isocode)[unique=true];stopword[unique=true]
2 ;electronicsIndex;en;the

Synonyms

Synonyms help you to deal with customers typo, abbreviations or requests, they
simply translate a word into something you know your SOLR index would easily
understand, for example let’s say a customer is looking for a disk capacity and
he enters ‘256 gigabytes’, you need to translate ‘gigabytes’ into ‘GB’ because
that’s how you have indexed your products.
In order to create a new one :
1 INSERT_UPDATE SolrSynonymConfig;facetSearchConfig(name)[unique=true];
language(isocode)[unique=true];synonymFrom[unique=true];synonymTo
2 ;electronicsIndex;en;"gigabytes";"GB"

Hero products & boost rules

Hero products

SAP Hybris gives the possibility to prioritize which products should appear on
top of the category listing by having hero products. Hero products work on a
category based level, it means that if you don’t navigate inside a given category
but instead do a normal search hero products have no influence on the result
sorting.
For example when a customer navigates to the Camera top category through the
top menu link (Accelerator store front) we want to display the product 478828
(10.2 Megapixel D-SLR with Standard Zoom Lens) first, below the Impex query
:
1 $productCatalog=electronicsProductCatalog
2 $productCatalogVersion=catalogVersion(CatalogVersion.catalog(Catalog.
id[default=$productCatalog]),CatalogVersion.version[default=
Online])[default=$productCatalog:Online]
3 INSERT_UPDATE SolrHeroProductDefinition;$productCatalogVersion[unique
=true];category(code, $productCatalogVersion);code[unique=true];
indexedType(identifier);products(code, $productCatalogVersion)
4 ;;575;575_electronicsProductType;electronicsProductType;478828
5
6 INSERT_UPDATE Product;code[unique=true];$productCatalogVersion[unique
=true];solrHeroProductDefinitions(code)
7 ;478828;;575_electronicsProductType

Now navigate to home -> open catalogue -> cameras -> digital cameras, you
should see your product on top of the search result.

Boost rules

Boost rules help you to adjust the SOLR server answers in the way that for
example product in stock would show up before out of stock products, based on
different factors you will artificially boost the results.
SAP Hybris implemented boosting at query time, meaning that you
do not need to re-index to see the changes!
For example you want the product 1312564 to always be on top you can execute
this Impex query :
1 $solrIndexedType=electronicsProductType
2
3 INSERT_UPDATE GlobalSolrSearchProfile;code[unique=true];indexedType(
identifier)
4 ;globalcatalog-srch-profile0000000001;$solrIndexedType
5
6 INSERT_UPDATE SolrBoostRule;propertyValue[unique=true];
solrIndexedProperty(name);operator(code)[unique=true];boostFactor
;solrSearchProfiles(code)
7 ;1312564;code;EQUAL_TO;100;globalcatalog-srch-profile0000000001

Now when you navigate to the Power Supplies category (one of the default top
navigation link) you see that our product 1312564 is listed on top.
Solr boost rule operators are :
• EQUAL_TO
• CONTAIN
• GREATER_THAN
• GREATER_THAN_OR_EQUAL_TO
• LESS_THAN
• LESS_THAN_OR_EQUAL_TO
Now if you type battery into your search box component you’d expect to see
your product 1312564 on top of the list, but it’s not ! The reason is that the
boost factor we entered (100) is not enough to push it to the top. A lot of other
factors are adding their boost rules, below a SOLR query executed when your
search for battery :
1 localhost:8983/solr/master_electronics_Product/select?
2 q=....'((code_string:battery^90.0)+
3 OR+(keywords_text_en:battery^20.0)+
4 OR+(manufacturerName_text:battery^40.0)+
5 OR+(categoryName_text_en_mv:battery^20.0)+
6 OR+(lastCustomerReview_string:battery^100.0)+
7 OR+(ean_string:battery^100.0)+
8 OR+(name_text_en:battery^50.0))+
9 OR+((keywords_text_en:battery~^10.0)+
10 OR+(manufacturerName_text:battery~^20.0)+
11 OR+(categoryName_text_en_mv:battery~^10.0)+
12 OR+(lastCustomerReview_string:battery~^50.0)+
13 OR+(name_text_en:battery~^25.0))+
14 OR+((code_string:battery*^45.0)+
15 OR+(ean_string:battery*^50.0))+
16 OR+((keywords_text_en:"battery"^40.0)+
17 OR+(manufacturerName_text:"battery"^80.0)+
18 OR+(categoryName_text_en_mv:"battery"^40.0)+
19 OR+(name_text_en:"battery"^100.0))'})+
20 //
21 // This is our custom boost query !
22 //
23 AND+({!func+v="sum(map(query({!v=code_string:1312564})
,0,0,0,1000.0))"})
24 //
25 &sort=score+desc,inStockFlag_boolean+desc,score+desc
26 &start=0&rows=20
27 &facet.field=Resolution,+80_string
28 &facet.field=Mounting,+1867_en_string
29 &facet.field=categoryPath_string_mv
30 &facet.field=Megapixel,+63_string
31 &facet.field=exportToGoogleShopping_boolean
32 &facet.field=availableInStores_string_mv
33 &facet.field=pickupAvailableFlag_boolean
34 &facet.field=Colour+of+product,+1766_en_string
35 &facet.field=price_usd_string
36 &facet.field=allPromotions_string_mv
37 &facet.field=allCategories_string_mv
38 &facet.field=Lens+type,+472_en_string_mv
39 &facet.field=category_string_mv
40 &facet.field=brand_string_mv
41 &facet=true
42 &facet.sort=count
43 &facet.mincount=1
44 &facet.limit=50
45 &spellcheck=true
46 &spellcheck.q=battery
47 &spellcheck.dictionary=en
48 &spellcheck.collate=true
49 &fq=(catalogId:"electronicsProductCatalog"+AND+catalogVersion:"
Online")

If you want to see the SOLR query you need to activate the debug
for de.hybris.platform.solrfacetsearch package :
1 log4j2.logger.search.name=de.hybris.platform.solrfacetsearch
2 log4j2.logger.search.level = debug
3 log4j2.logger.search.appenderRef.stdout.ref = STDOUT

Having a boost of 100 is not enough, so why not putting more to be sure that our
product is always showing on top, by default SAP Hybris limits the maximum
boost factor to 100, if you want to increase it you need to change the out of
the box BoostRuleValidator behavior, unfortunately SAP Hybris didn’t think
that this could need to be easily updated and made all beans around it without
aliases, so in order to change the maxBoostFactorValue attribute you have 3
options :
• change it directly under
commercesearch/resources/commercesearch-spring.xml, but changing
SAP Hybris source files means it’s hard to update to newer
versions….
• import boost factor rules in legacy mode (without service layer
interceptors)
• using Spring AOP to update the existing bean, the preferred solution
from far
How to change boostRuleValidator bean using AOP, first you need to create a
class to handle the change, this would be called around the validate method call
from the interceptor :
1 package com.hybhub.hybhubaddon.commercesearch.searchandizing.boost.
interceptors;
2
3 import de.hybris.platform.commercesearch.searchandizing.boost.
interceptors.BoostRuleValidator;
4 import org.aspectj.lang.ProceedingJoinPoint;
5 import org.springframework.beans.factory.annotation.Required;
6

7 public class HybhubBoostRuleValidatorAspect


8 {
9 private int maxBoostFactorValue;
10 public void around(final ProceedingJoinPoint joinPoint) throws
Throwable
11 {
12 final BoostRuleValidator boostRuleValidator = (
BoostRuleValidator) joinPoint.getTarget();
13 boostRuleValidator.setMaxBoostFactorValue(maxBoostFactorValue
);
14 joinPoint.proceed();
15 }
16

17 @Required
18 public void setMaxBoostFactorValue(final int maxBoostFactorValue)
19 {
20 this.maxBoostFactorValue = maxBoostFactorValue;
21 }
22 }

Now you need to configure your aspect with Spring, we use an around aspect
to be able to inject our customized max boost factor into the existing bean :
1 <bean id="hybhubBoostRuleValidatorMethodInterceptor"
2 class="com.hybhub.hybhubaddon.commercesearch.searchandizing.boost
.interceptors.HybhubBoostRuleValidatorAspect">
3 <property name="maxBoostFactorValue" value="500" />
4 </bean>
5
6 <aop:config>
7 <aop:aspect id="boostValidatorAspect" ref="
hybhubBoostRuleValidatorMethodInterceptor">
8 <aop:pointcut id="boostValidatorPoincut"
9 expression="execution(* de.hybris.platform.commercesearch
.searchandizing.boost.interceptors.BoostRuleValidator
.onValidate(..))" />
10 <aop:around method="around" pointcut-ref="
boostValidatorPoincut"/>
11 </aop:aspect>
12 </aop:config>
You can now have boost factor value up to 500, if you run this Impex query
your product 1312564 will always be on top of search :
1 INSERT_UPDATE SolrBoostRule;propertyValue[unique=true];
solrIndexedProperty(name);operator(code)[unique=true];boostFactor
;solrSearchProfiles(code)
2 ;1312564;code;EQUAL_TO;500;globalcatalog-srch-profile0000000001
Chapter 7

Platform basics

SAP Hybris commerce platform is composed of a set of essential features :


• persistence
• caching
• security
• transactions
• clustering
• i18n
• import/export
• search
• cronjobs
• task queue

Initialization
Initialization creates the database and inject the data from scratch following
these steps:
• Put together all items.xml files to create the type system definition
• Aborts all running cronjobs
• Remove all tables existing under the type system definition, orphaned data
stay intact
• Hybris goes through all extension manager and call: initialize Remove
Objects, initialize Create Types, initialize Modify Types and initialize
Create Objects
• Prepare the DDL (Data Definition Language) and the DML (Data
Modification Language)
• Clears cache
• Creates media folders

124
• Sets license
• Always creates essential data and if enabled project data
Hybris no longer removes all tables, it removes only those that are
declared in its current items.xml files, to reactivate the legacy
behavior use initialization.legacy.mode=true in local.properties
To run the initialization you have 2 options :
• from the SAP Hybris HAC (Hybris Administration Console)
• from the build framework, executing ant initialize, one option is to select
the tenant with -Dtenant=master
On a production system it is a good idea to lock the initialization
from the HAC, configure system.unlocking.disabled=true

Update
During the update process SAP Hybris update the item types to match the new
items.xml definition, unlike the initialization process there are no loss of data
during an update because update process :
• doesn’t rename tables
• doesn’t rename attributes
• doens’t change an attribute type
• doesn’t drop any table
• doesn’t delete any data
• change indices by recreating them
• doesn’t modify an attribute from optional to required
During the update process SAP Hybris will (in order of execution) :
• Put together all items.xml files to create the type system definition
• Update existing type system according to the new items.xml definition (if
possible, see rules above)
• Add new type system
• create essential data and project data (if enabled)
On a production system it is a good idea to lock the initialization
from the HAC, configure system.unlocking.disabled=true

Update and Initialization lock


Whenever you start an update or an initialization, SAP Hybris will get a lock to
be sure no one is starting a similar process before it ends. The lock is obtained
for a special database table SYSTEMINIT, here is an example of a lock during
an update :
1 MariaDB [hybris]> select * from SYSTEMINIT;

id locked tenantId clusterNode lockdate process instanceId


globalID 1 master 0 20… System update …

locked = 1 means you cannot start an update or an initialization.

Update and Initialization hooks


You can control what an extension is doing during the initialization and update
process, SAP Hybris provides annotation hooks for you to control the execution.
To create your own hook you need to create a class that uses the annotation
SystemSetup here example using AbstractSystemSetup from commerceservices as
a starting point :
1 package com.hybhub.setup;
2

3 import de.hybris.platform.commerceservices.setup.AbstractSystemSetup;
4 import de.hybris.platform.core.initialization.SystemSetup;
5 import de.hybris.platform.core.initialization.SystemSetup.Process;
6 import de.hybris.platform.core.initialization.SystemSetup.Type;
7 import de.hybris.platform.core.initialization.SystemSetupContext;
8 import de.hybris.platform.core.initialization.SystemSetupParameter;
9 import de.hybris.platform.core.initialization.
SystemSetupParameterMethod;
10

11 import java.util.ArrayList;
12 import java.util.List;
13

14 import org.slf4j.Logger;
15 import org.slf4j.LoggerFactory;
16

17 import com.hybhub.constants.HybhubhookConstants;
18

19 @SystemSetup(extension = HybhubhookConstants.EXTENSIONNAME)
20 public class HybhubHookSystemSetup extends AbstractSystemSetup
21 {
22

23 final static Logger LOG = LoggerFactory.getLogger(


HybhubHookSystemSetup.class);
24

25 @SystemSetupParameterMethod
26 @Override
27 public List<SystemSetupParameter> getInitializationOptions()
28 {
29 final List<SystemSetupParameter> params = new ArrayList<>();
30 params.add(createBooleanSystemSetupParameter("key", "Import ?
", false));
31 return params;
32 }
33

34 @SystemSetup(type = Type.ESSENTIAL, process = Process.ALL)


35 public void createEssentialData(final SystemSetupContext context)
36 {
37 final boolean doImport = getBooleanSystemSetupParameter(
context, "key");
38 if (doImport)
39 {
40 logInfo(context, "Starting importing essential data for "
+ HybhubhookConstants.EXTENSIONNAME);
41 importImpexFile(context, "/hybhubcore/essential.impex");
42 synchCatalogs();
43 }
44 else
45 {
46 logError(context, "Did not import essential data !", null
);
47 }
48 }
49

50 @SystemSetup(type = Type.PROJECT, process = Process.ALL)


51 public void createProjectData(final SystemSetupContext context)
52 {
53 final boolean doImport = getBooleanSystemSetupParameter(
context, "key");
54 if (doImport)
55 {
56 logInfo(context, "Starting importing project data for " +
HybhubhookConstants.EXTENSIONNAME);
57 importImpexFile(context, "/hybhubcore/project.impex");
58 synchCatalogs();
59 }
60 else
61 {
62 logError(context, "Did not import project data !", null);
63 }
64 }
65

66 private void synchCatalogs()


67 {
68 getSetupSyncJobService().createContentCatalogSyncJob("
electronicsContentCatalog");
69 getSetupSyncJobService().createProductCatalogSyncJob("
electronicsProductCatalog");
70 }
71 }

You need to declare the system setup class as a bean :


1 <bean id="hybhubHook" class="com.hybhub.setup.HybhubHookSystemSetup"
parent="abstractCoreSystemSetup"/>

Have a look at coreDataImportService, sampleDataImportService


and event services, to find an example you could open
ElectronicsStoreSystemSetup

Essential & project data

Import by convention

During the initialization and update processes, the platform looks for ImpEx
files under /resources/impex folder. In particular:
• For essential data: The platform scans the /resources/impex folders for
files with names that match the regular expressionessentialdata.impex*
and imports the files during the essential data creation.
• For project data: The platform scans the /resources/impex folders for
files with names that match the regular expressionprojectdata.impex* and
imports the files during the project data creation.
The ImpEx directory does not exist by default. You must create it and copy
files to it.

Import by configuration

If you have special folder structures or want to use another folder in the resources,
you must override the configuration in your local.properties file:
• For essential data, add the property .essentialdata-impex-pattern.
• For project data, use .projectdata-impex-pattern.
For example, assume that you have the following folder structure:
• resources/test1.impex
• resources/subfolder/test2.impex
• resources/impex/subfolder/subfolder/test3.impex
In this structure, only the test1.impex file has the pattern .essentialdata-impex-
pattern=*.impex.
In contrast to the example above, the pattern
.essentialdata-impex-pattern=/.impex* includes test1.impex, test2.impex and
test3.impex. If you want your configuration to work as the default does, you
must set the pattern to
.essentialdata-impex-pattern=impex/essentialdata*.impex.

Control the order of import

If you need to control in what order the Impex files are being imported, you can
create a file that match the import pattern, and from this files you will import
all the other Impex files you need in the wanted order :
1 "#% impex.includeExternalData(SampleDataManager.class.
getResourceAsStream(""/firstFileToBeImported.csv""), ""utf-8"",
0, 0 );";
2 "#% impex.includeExternalData(SampleDataManager.class.
getResourceAsStream(""/secondFileToBeImported.csv""), ""utf-8"",
0, 0 );";

Sessions handling
All browser requests made to SAP Hybris are bind to a session there are 2 kind
of sessions :
• the HTTP session which is by default held by Tomcat
• the JaloSession held by SAP Hybris
The layer Jalo is deprecated, but JaloSessions are not going to be
replaced by the service layer, they just use a legacy name.
The JaloSession is a wrapper around the HTTP session to hold information
about the current SAP Hybris user :
• user (anonymous by default)
• language
• currency
• price factory
• locale
• timezone
Jalo Sessions are also used for cronjobs, they exist only within SAP Hybris
memory and are by default never persisted.
Example how to get your current Jalo Session from the SessionService (Groovy
script) :
1 def sessionService = spring.getBean("sessionService")
2 def jaloSession = sessionService.getCurrentSession().getJaloSession()
3 def sessionContext = jaloSession.getSessionContext()
4

5 println jaloSession.getHttpSessionId()
6 println sessionContext.getLanguage()
7 println sessionContext.getLocale()

Extensions structures
SAP Hybris is made of different extensions, like the set of extensions that
constitute the so called platform. Extensions are made to be independent from
each other, so you could migrate SAP Hybris platform without changing your
customized extensions.
Each extensions are represented by a Java project, even the out of the box
extensions can be opened as Java projects, below the folder’s structure of all
extensions :
• lib folder for external libraries
• resources folder for configuration and localization
• src folder for source code
• testsrc folder for the tests
• web folder for the we application
• buildcallbacks.xml file for build call backs configuration
• extensioninfo.xml extension configuration
• project.properties extension properties
• external-dependencies.xml libraries managed by maven

extensioninfo.xml

Within the extensioninfo.xml file you can configure :


• list of dependencies, this will be used by the build framework to know
what extensions need to be included within the build and in what order
they should be compiled
• activated modules
– core module, if defined the extension will be used to define and
localize item types trough the *items.xml file.
– web module, if activated the extension will be used as a web
application
– hmc, if activated the extension will have hmc configuration
meta, there are also different meta keys that can be used to configure
extensions, for backoffice or templates for example.
1 <meta key="backoffice-module" value="true"/>
2 <meta key="extgen-template-extension" value="true"/>
3 <meta key="modulegen-name" value="accelerator,b2baccelerator,
chinaaccelerator"/>

localextensions.xml

SAP Hybris consists of a number of extensions, you configure which extensions


are used by modifying the localextensions.xml file located under your
configuration folder.
Extensions located under ${HYBRIS_BIN_DIR}/platform/ext are
automatically loaded
Extensions are loaded when :
• you configure a directory (relative to ${HYBRIS_BIN_DIR} or not)
• you configure a name, if it can be found within a configured path
• by dependency, if it can be found within a configured path
• by being inside a folder configured as auto-loaded
Examples :
1 <extension dir="${HYBRIS_BIN_DIR}/custom/hybhubaddon"/>
2
3 <path dir='${HYBRIS_BIN_DIR}/custom' autoload='false' />
4 <extension name="hybhubaddon"/>
5
6 <path dir='${HYBRIS_BIN_DIR}/custom' autoload='true' />

It’s also possible to load external web application (war files for
example), using the webapp tag :
1 <webapp context="/path/to/your/context.xml" path="/mypath"/>

During the build phase you can read what extensions are being loaded directly,
and what extensions are being lazy loaded (through dependencies and configured
path) :
1 ...
2 [echo] -----
3 [echo] --- Extensions in dependency order ( options:
4 [echo] --- @deprecated: is deprecated, p: platform extension,*: auto
-required
5 [echo] --- ?: lazy-loaded, i: got items.xml, b: got beans.xml, c:
got core module
6 [echo] --- w: got web module, h: got HMC module )
7 [echo] -----
8 [echo] core 6.0.0.0-SNAPSHOT [p*cib]
9 [echo] testweb 6.0.0.0-SNAPSHOT [p*w]
10 [echo] scripting 6.0.0.0-SNAPSHOT [p*ci]
11 ....

Create a new extension

You can create new extensions based on an existing template, below example
create a new extension base on the yempty template :
1 $ platform ant extgen
2 ...
3 ...
4 [input]
5 [input] Please choose a template for generation.
6 [input] Press [Enter] to use the default value (ywebservices,
ysmarteditmodule, yoccaddon, yhacext, [yempty],
ycommercewebservices, ycommercewebservicestest,
ycommercewebserviceshmc, ycmssmartedit,
ychinaacceleratorstorefront, yatddtests, yaddon,
yacceleratorstorefront, yacceleratorordermanagement,
yacceleratorfulfilmentprocess,
yacceleratorfractusfulfilmentprocess, yscala, ygroovy,
ycockpit, ybackoffice, hybhubstorefront,
hybhubfulfilmentprocess)
7 yempty
8 [input]
9 [input] Please choose the name of your extension. It has to start
with a letter followed by letters and/or numbers.
10 [input] Press [Enter] to use the default value [training]
11 myextension
12 [input]
13 [input] Please choose the package name of your extension. It has
to fulfill java package name convention.
14 [input] Press [Enter] to use the default value [org.training]
15 com.hybhub
16 ...

There are different available templates to create new extensions, the


convention is that all extensions starting with a y are templates, the
most basic one is the yempty template which is an empty shell with
the SAP Hybris folder structure.

Maven

SAP Hybris is currently in between Ant and Maven, the whole platform build
is tightly coupled with Ant but dependency management can be used for any
extension. Also for some modules (CIS and Datahub for example) the full
lifecycle is done with Maven.
If you want to activate dependency management for one of your extension open
the extensioninfo.xml file and configure it with usemaven=”true” :
1 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2 <extensioninfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="extensioninfo.xsd">
3 <extension abstractclassprefix="Generated" classprefix="
Hybhubhook" managername="HybhubhookManager"
4 managersuperclass="de.hybris.platform.jalo.extension.
Extension" name="hybhubhook" usemaven="true">
5 <requires-extension name="commerceservices" />
6 <coremodule generated="true" manager="com.hybhub.jalo.
HybhubhookManager" packageroot="com.hybhub" />
7 <webmodule jspcompile="false" webroot="/hybhubhook" />
8 </extension>
9 </extensioninfo>

Then you can manage your dependencies inside external-dependencies.xml:


1 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://
www.w3.org/2001/XMLSchema-instance"
2 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://
maven.apache.org/xsd/maven-4.0.0.xsd">
3 <modelVersion>4.0.0</modelVersion>
4 <groupId>de.hybris.platform</groupId>
5 <artifactId>hybhubhook</artifactId>
6 <version>5.0.0.0-SNAPSHOT</version>
7 <packaging>jar</packaging>
8 <dependencies>
9 <dependency>
10 <groupId>org.apache.commons</groupId>
11 <artifactId>commons-collections4</artifactId>
12 <version>4.1</version>
13 </dependency>
14 </dependencies>
15 </project>

When you build your project Hybris will automatically download all libraries
and update your project, if you want to update your project classpath you can
use ant classpathgen within your extension.
You need to have Maven installed!

Configuration
SAP Hybris uses simple property files for its configuration, all variables would
be either injected into Tomcat when you execute ant server, or injected into
the running system as configuration variables (you can configure them lively
directly from the HAC).
There are different files where you can configure SAP Hybris behavior, in order
of priority from high to low :
• config/local.properties
• your extensions project.properties files
• platform directory project.properties file
Configuration properties are defined using a key and a value, example :
1 #A comment
2 the.key=myValue

Use {tab} for tabulation, \t is ignored.


The recommended way of configuring SAP Hybris is to configure extensions with
default configuration within their own project.properties files, and configure your
project for a given environment within your local.properties file.
Never change the configuration directly into out of the box extensions
of within the platform project.properties file. This would make your
it harder to migrate to newer versions.
Restarting your server is enough for your configuration to changes to
be loaded you don’t need to re-build the platform.

Configuration Service

Example how to get a configuration key from your code :


1 def configurationService = spring.getBean("configurationService")
2 def value = configurationService.getConfiguration().getProperty("
spring.profiles.active")

You can read or edit the current configuration, have a look at the interface
org.apache.commons.configuration.Configuration.

Environment variables

When configuration files may contain sensible data such as logins, passwords,
urls, hash… It’s a good idea not to store them within a file. SAP Hybris gives you
the possibility to configure special properties value that need to be overridden
by environment variables using keyword, for example within my configuration
I have :
1 hybhub.config=<CHANGE_ME>

Then from my environment I execute (note that it needs to start with y_ and
you replace dots by underscore, double underscore to replace single underscores)
:
1 export y_hybhub_config=fromConsole

Then from the HAC :


1 def configurationService = spring.getBean("configurationService")
2 def value = configurationService.getConfiguration().getProperty("
hybhub.config")

Will print fromConsole.

Runtime optional configuration

It becomes difficult to maintain configuration for various environment from a


single repository, usually the config folder is duplicated for each environment,
and every few weeks a developer would forget to copy the new configuration he
added to the pre-production environment to the production environment leading
to half a day of debugging.
SAP Hybris version 6 introduced a new concept of an optional configuration
directory, to specify host specific properties without interfering with provided
configuration file, to do so you need to configure an extra directory :
• from your local.properties using hybris.optional.config.dir key
• from an environment variable using HYBRIS_OPT_CONFIG_DIR
In this folder files would be loaded in they match [1-9][0-9]-local.properties
(example : 10-local.properties), the number specifies the order in which they
are loaded and merged.

Build
SAP Hybris build framework is based on :
• Apache Ant, automation framework build in Java
• Eclipse IDE
When you execute the command ant, the build framework would call the default
ant target (all -> build + server) :
• check directories (data, temp and log), it creates the folders if they don’t
exist
• check the config directory, and prompt for the configuration template
selection if none exist
• resolves extensions dependencies
– you cannot predict the order extensions are being built
– extensions that depends on another are built only after all their
dependencies are built
• generates and compiles source files (according to the definitions in the
*items.xml files)
• collects localization property files (locales_XY.properties)
• collects layout configuration files (hmc.xml)
• updates the hybris Server
You can use ant with different scopes :
• platform, will execute the target for all extensions
• extension, will execute the target for a single extension
To see all ant targets, you can use ant -p.
Unless you execute ant clean Java classes are not compiled every time
you call ant all, because the javac command will compare timestamp
of the source and target and compile the source only if its timestamp
is newer than the target

Callbacks

In each extensions you will find a file named buildcallbacks.xml, within this file
you can extend the behavior of the build framework for a given extension adding
custom actions around each ant targets, for example before my extension is build
:
1 <macrodef name="hybhubhook_before_build">
2 <sequential>
3 <echo message="Hybhub is being build !!" level="info"/>
4 </sequential>
5 </macrodef>

Tenant
SAP Hybris can run in a multi tenant mode, meaning that each tenant are using
a different set of data.
Each tenant has :
• isolated data
• option to have a separate database
• option to use a different time zone and locales
• option to use different extensions
To declare new tenants :
1 installed.tenants=junit,foo,t1,t2,hybhub

The master tenant is always present


To have specific tenant configuration you need to create as
tenant_{tenantID}.properties under your configuration folder.
Under our tenant specific configuration you can configure extensions to use using
the following two properties :
1 allowed.extensions=core;promotions
2 forbidden.extensions=b2bapprovalprocess;hybhubaddon

Cache
SAP Hybris cache helps to reduce the number of database queries, it caches
three type of objects :
• Flexible Search Queries results
• Item instances
• Item attributes
The cache is used within the Service Layer, it is completely transparent to use
it, when you call a getter on an item attribute, if it hasn’t been loaded yet it
would be loaded from the database and cached for the next time. The cache is
independent for each node meaning that each nodes have their local cache.
Data are removed from the cache when :
• Cache is full and the replacement strategy is removing an entry
• Cache is no longer valid :
• item is deleted
• item is modified
When a node invalidates a cache entry, the invalidation is shared with other
nodes by sending a UDP request to all cluster nodes.

Region cache

SAP Hybris cache is divided into region, each region has its own configuration,
caches different kind of objects and has a maximum size. Regions can have
different kind of eviction strategy :
• Least Recently Used (LRU), objects are evicted based on their last used
timestamp
• Least Frequently Used (LFU), every time an object is read the cache
increment a hit counter, object are evicted based on this counter
• First In First Out (FIFO), objects are evicted based on their age
By default SAP Hybris has a region for type systems, the region is called
ehCacheEntityCacheRegion and uses LRU eviction strategy.
To create new cache region you need to create a new Spring Beans within the
global Spring context, first I configure for my extension named hybhubhook a
new global spring context file :
1 hybhubhook.global-context=hybhubhook-cache-spring.xml

Then I create a new file under the resources folder hybhubhook-cache-spring.xml


:
1 <?xml version="1.0" encoding="UTF-8"?>
2 <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www
.springframework.org/schema/aop"
3 xmlns:c="http://www.springframework.org/schema/c"
4 xsi:schemaLocation="http://www.springframework.org/schema/beans
5 http://www.springframework.org/schema/beans/spring-beans.
xsd
6 http://www.springframework.org/schema/aop
7 http://www.springframework.org/schema/aop/spring-aop.xsd"
8 default-lazy-init="true">
9 <bean id="productCacheRegionRegistrar" class="de.hybris.platform.
regioncache.region.CacheRegionRegistrar" c:region-ref="
productCacheRegion" />
10 <alias name="defaultProductCacheRegion" alias="productCacheRegion
" />
11 <bean name="defaultProductCacheRegion" class="de.hybris.platform.
regioncache.region.impl.EHCacheRegion" lazy-init="false">
12 <constructor-arg name="name" value="productCacheRegion" />
13 <constructor-arg name="maxEntries" value="1" />
14 <constructor-arg name="evictionPolicy" value="LFU" />
15 <constructor-arg name="statsEnabled" value="true" />
16 <constructor-arg name="exclusiveComputation" value="true" />
17 <property name="handledTypes">
18 <array>
19 <value>1</value>
20 </array>
21 </property>
22 </bean>
23 </beans>

handledTypes is the type code of the item type, one is for products.
It could also be ALL_TYPES, QUERY_CACHE or NO_QUERY.
For more examples have a look at the SAP Hybris default regions
cache within core-cache.xml.
Now if you go into the HAC, under /monitoring/cache you should see your new
cache region productCacheRegion.

Interceptors
The service layer gives the ability to activate interceptor when life cycle of a
model reaches certain steps :
• load interceptor
(de.hybris.platform.servicelayer.interceptor.LoadInterceptor) is loaded
when the service layer loads an item. You may use this interceptor to
change or check values loaded by the service layer.
• init default interceptor
(de.hybris.platform.servicelayer.interceptor.InitDefaultsInterceptor) is
called when you create a new item from the model service. You may use
this interceptor to fill the item with default value you couldn’t configure
from the *items.xml
• prepare interceptor
(de.hybris.platform.servicelayer.interceptor.PrepareInterceptor) is called
before an item is saved by the service layer. You may use this interceptor
to add or update attribute values before they are saved
• validate interceptor
(de.hybris.platform.servicelayer.interceptor.ValidateInterceptor) is called
before an item is saved and after it has been prepared. You may use this
interceptor to validate the integrity of the data
• remove interceptor
(de.hybris.platform.servicelayer.interceptor.RemoveInterceptor) is called
before an item is being removed by the service layer. You may use this
interceptor to prevent removal of data or to delete related data.
Example on how to create an interceptor for product items :
1 package com.hybhub.hybhubaddon.servicelayer.interceptor;
2

3 import de.hybris.platform.core.model.product.ProductModel;
4 import de.hybris.platform.servicelayer.interceptor.InterceptorContext
;
5 import de.hybris.platform.servicelayer.interceptor.
InterceptorException;
6 import de.hybris.platform.servicelayer.interceptor.RemoveInterceptor;
7

8 import java.util.regex.Pattern;
9

10 import org.slf4j.Logger;
11 import org.slf4j.LoggerFactory;
12

13

14 public class ProductRemoveInterceptor implements RemoveInterceptor<


ProductModel>
15 {
16

17 final private static Logger LOG = LoggerFactory.getLogger(


ProductRemoveInterceptor.class);
18

19 final private static Pattern PROTECTED_PRODUCTS = Pattern.compile


("^[0-9]+$");
20

21 @Override
22 public void onRemove(final ProductModel prd, final
InterceptorContext ctx) throws InterceptorException
23 {
24 LOG.info("Removing product : " + prd.getCode());
25 if (PROTECTED_PRODUCTS.matcher(prd.getCode()).find())
26 {
27 throw new InterceptorException("Product is protected,
cannot remove it !");
28 }
29 LOG.info("Product : " + prd.getCode() + " removed");
30 }
31 }
You need to declare the interceptor as a Spring bean and to configure the type
mapping :
1 <alias name="defaultProductRemoveInterceptor" alias="
productRemoveInterceptor" />
2 <bean id="defaultProductRemoveInterceptor" class="com.hybhub.
hybhubaddon.servicelayer.interceptor.ProductRemoveInterceptor" />
3 <bean id="productRemoveInterceptorMapping" class="de.hybris.platform.
servicelayer.interceptor.impl.InterceptorMapping">
4 <property name="interceptor" ref="productRemoveInterceptor" />
5 <property name="typeCode" value="Product" />
6 </bean>

Now try to delete a product with a numeric code, the interceptor should block
you from removing it.
The InterceptorMapping can be also configured with :
• a replacedInterceptors collection, if you want to replace existing
interceptors
• an order of priority to run them in a sequence if there are multiple
interceptors
You can choose to disable interceptors from an Impex query, by
types [disable.interceptor.types=validate] or by bean names
[disable.interceptor.beans=‘productRemoveInterceptor’]
You can choose to call the service layer in a local view with interceptor
deactivated :
1 final Map<String, Object> params = ImmutableMap.of(
InterceptorExecutionPolicy.DISABLED_INTERCEPTOR_TYPES,
2 ImmutableSet.of(InterceptorExecutionPolicy.
DisabledType.VALIDATE));
3 sessionService.executeInLocalViewWithParams(params, new
SessionExecutionBody()
4 {
5 @Override
6 public void executeWithoutResult()
7 {
8 modelService.save(item); // executed without any validate
interceptors
9 }
10 });
Transactions
Transactions are used to keep the data consistent at any time, SAP Hybris
provides a wrapper to easily work with transactions.
Simple groovy example :
1 def transaction = de.hybris.platform.tx.Transaction.current()
2

3 transaction.begin()
4

5 //commit all changes


6 transaction.commit()
7

8 //rollback all changes


9 transaction.rollback()

A single thread can only have one transaction, therefore it doesn’t


matter how many times you get the current transaction, if it’s from
the same thread you will always get the same transaction !
Remember to execute commit and rollback within a finally block !
Errors are not caught by Exception blocks.
SAP Hybris also has a more advanced wrapper to include all steps of a
transactions, the TransactionBody the pro is that you don’t need to manually
handle the transactions over and over :
1 Transaction.current().execute( new TransactionBody()
2 {
3 public <Object> Object execute()
4 {
5 //Everything here is contained within a single transaction
6 return something;
7 }
8 }
9 );

SAP Hybris offers a delayed store mechanism, if activated statements


will be executed only when the transaction is committed, the pro
is that performance would be better in big transactions but data
won’t be updated and available until the transaction is committed.
To activate it Transaction.current().enableDelayedStore(true);

Tasks
SAP Hybris provides a task service with the following features :
• Scheduling, time and event based
• Cluster aware, a task may be executed by any of the available node
• pool of workers, to avoid to overload the cluster with too many tasks, there
is a maximum number of running workers (see project.properties from the
processing extension)
Chapter 8

Platform core

Events
The Event System is a framework provided by the service layer allowing you to
send and receive events within the SAP Hybris.
• One software component acts as a source and publishes an event that is
received by registered listeners
• Event listeners are objects that are notified of events and perform business
logic corresponding to the event that occurred
• Events can be published locally or across cluster nodes
• SAP Hybris Event System is based on the Spring event system
To create your own event, you need to extend the class
de.hybris.platform.servicelayer.event.events.AbstractEvent :
1 package com.hybhub.event;
2

3 import de.hybris.platform.servicelayer.event.events.AbstractEvent;
4

5 public class HybhubEvent extends AbstractEvent


6 {
7 private final String name;
8

9 public HybhubEvent(final String name)


10 {
11 this.name = name;
12 }
13

14 @Override
15 public String toString()

144
16 {
17 return "Hybhub Event : " + this.name;
18 }
19 }

Then to create a listener you extend


de.hybris.platform.servicelayer.event.impl.AbstractEventListener :
1 package com.hybhub.event;
2

3 import de.hybris.platform.servicelayer.event.impl.
AbstractEventListener;
4

5 import org.slf4j.Logger;
6 import org.slf4j.LoggerFactory;
7

9 public class HybhubListener extends AbstractEventListener<HybhubEvent


>
10 {
11

12 private static final Logger LOG = LoggerFactory.getLogger(


HybhubListener.class);
13

14 @Override
15 protected void onEvent(final HybhubEvent hybhubEvent)
16 {
17 LOG.info("Received event(Hybhub Event) : " + hybhubEvent);
18 }
19

20 }

Finally you need to create a Spring bean for your listener :


1 <bean id="hybhubListener" class="com.hybhub.event.HybhubListener"
2 parent="abstractEventListener" />

To try you event run this Groovy script :


1 import com.hybhub.event.HybhubEvent
2 def eventService = spring.getBean("eventService")
3

4 eventService.publishEvent(new HybhubEvent("Event published from


Groovy console !"))

You should be able to read the following message on SAP Hybris console : INFO
[hybrisHTTP8] [HybhubListener] Received event(Hybhub Event) : Hybhub Event
: Event published from Groovy console !
The only flaw here is that everything is executed synchronously by the same
thread ! To process them in an asynchronous way you can :
• make your event cluster aware by implementing
de.hybris.platform.servicelayer.event.ClusterAwareEvent, when you
implement this interface your events are always processed asynchronously
even if they are executed on the same node they were created
1 package com.hybhub.event;
2

3 import de.hybris.platform.servicelayer.event.ClusterAwareEvent;
4 import de.hybris.platform.servicelayer.event.events.AbstractEvent;
5

6 import org.slf4j.Logger;
7 import org.slf4j.LoggerFactory;
8

10 public class HybhubEvent extends AbstractEvent implements


ClusterAwareEvent
11 {
12 private static Logger LOG = LoggerFactory.getLogger(HybhubEvent.
class);
13

14 private final String name;


15

16 public HybhubEvent(final String name)


17 {
18 LOG.info(Thread.currentThread().getName());
19 this.name = name;
20 }
21

22 @Override
23 public String toString()
24 {
25 LOG.info(Thread.currentThread().getName());
26 return "Hybhub Event : " + this.name;
27 }
28

29 @Override
30 public boolean publish(final int sourceClusterId, final int
targetClusterId)
31 {
32 return true; //Returning true means your event will be
broadcasted on all nodes
33 }
34 }
• update the Spring bean platformClusterEventSender with an executor :
1 <bean id="platformClusterEventSender" class="de.hybris.platform.
servicelayer.event.impl.PlatformClusterEventSender">
2 <property name="serializationService" ref="serializationService"/
>
3 <property name="tenant" ref="tenantFactory"/>
4 <property name="executor">
5 <bean class="java.util.concurrent.Executors" factory-method="
newCachedThreadPool"/>
6 </property>
7 </bean>

Impex
SAP Hybris needs to exchange a lot of data with external systems and it needs
to be easily configurable without having to create complex SQL query, Impex
offers a way to easily store and exchange, it means import and export, it is an
out of the box CSV based import framework, from an impex file you can :
• import data
• update data
• import / update data
• remove data
• export data
Impex are useful for:
• initial data injection (stores definitions, initial catalogs, cms components
creation, catalogs creation…)
• update data during runtime
• test datas / configurations during development
• migrate data between systems
• backups
An Impex query has :
• a header defining the mapping between an item type and the value lines
• line value(s) defining the date
• comments
• macro definition
• BeanShells directive
• user rights definition
Eclipse Neon (impexeditor Feature, with live Impex validation if
your server is started) and IntelliJ (Hybris integration) have a
special editors available for Impex files.
Header

Header is a single line preceding the value lines, a header has :


• a mode which defines what kind of operations you are executing, it can
be :
– INSERT, creates a new item
– UPDATE, update an existing item based on unique identifiers
– INSERT_UPDATE, update an existing item if it can find the
unique identifier otherwise create a new entry
– REMOVE, try to remove an item based on unique attributes, log
a warning if it can’t find any elements
• a item type, like User or Product
• attributes of the related item type, like code, name
• attribute modifiers, gives additional processing instructions of a given
attribute
– alias for export ([alias=theAlias])
– allownull ([allownull=true]), not compatible with the service layer
– cellDecorator
([cellDecorator=de.hybris.platform.catalog.jalo.classification.eclass.EClassSuperCategoryDecorator])
– collection-delimiter, , is the default delimiter
([collection-delimiter=;])
– dateformat ([dateformat=dd-MM-yyyy])
– default ([default=‘default value’])
– forceWrite ([forceWrite=true), not compatible with the service layer
– ignoreKeyCase ([ignoreKeyCase=true])
– ignorenull ([ignorenull=true]), ignore null for collection type imports
– key2value-delimiter ([key2value-delimiter=->]), specifies the
operator to delimit keys and values
– lang ([lang=en])
– map-delimiter ([map-delimiter=|])
– mode ([mode=append]) for collections import append the collections,
replace or remove elements
– numberformat ([numberformat=#.###,##])
– path-delimiter ([path-delimiter=:])
– pos ([pos=3]) change positions of values, not recommended
– translator
([translator=de.hybris.platform.impex.jalo.translators.ItemPKTranslator])
– unique ([unique=true]) used to mark this attribute as unique, can be
configured on multiple attributes if needed
– virtual ([virtual=true,default=value]) needs to have a default modifier
as well
• header modifiers, are configured with the item type, for example : INSERT
MyType[headerModifier=something];…
– batchmode ([batchmode=true]), used with an update or remove it
allows to modify more than one item that matches the query
– cacheUnique ([cacheUnique=true])
– processor
([processor=de.hybris.platform.impex.jalo.imp.DefaultImportProcessor])
– impex.legacy.mode ([impex.legacy.mode=true])
Impex header syntax is case sensitive
Example with Title item type :
1 INSERT Title;code;name[lang=en]
2
3 UPDATE Title;code[unique=true];name[lang=en]
4
5 INSERT_UPDATE Title;code[unique=true];name[lang=en]
6
7 REMOVE Title;code[unique=true];name[lang=en]

You can also specify a subtype of the Header item type on the value line, for
example :
1 INSERT User;uid[unique=true]
2 Customer;aCustomer
3 Employee;anEmployee

The header item type could be abstract, but the value line item type
obviously can’t
Setting an attribute value for atomic types is straightforward, a string attribute
for example can be directly entered within the value (see example with User
item type above), but for reference attributes Impex expects you to enter the
primary key of the referenced item, this is not possible to know items primary
key before they are created so this is not the right way to create relations. To
efficiently and without external dependencies insert relations between items you
need to lookup for them based on their own attributes.
1 INSERT Product;code;unit(code);catalogVersion(catalog(id), version)
2 ;product;pieces;electronic:Staged

To localized attributes you need to use a modifier within the header attributes
like [lang=en] to localize an attribute in English :
1 INSERT Type;localizedAttribute[lang=en]

en is defined with the Language items and correspond to unique ISO


code of the language, have a look at the internationalization tab under
the HMC or HAC
Comment

A commented line starts with a dash # and are completely ignored during
import :
1 INSERT_UPDATE Product;code
2 #Begin importing products
3 ;product1;
4 #Finished importing products

Macro

Impex files can easily be huge, it’s not occasional to see Impex import files of
more than a thousand lines ! If you need to update one common attribute for
each of the value lines Macros come in handy. A Macro definition starts with a
$ sign :
1 #Macro definition
2 $unit=pieces
3 $variantType=LaptopVariant
4 $aid=MBP-
5 $manufacturer=Apple
6
7 $catalogVersion=catalogversion(catalog(id[default=$productCatalog]),
version[default='Staged'])[unique=true,default=$productCatalog:
Staged]
8 $supercategories=supercategories(code, $catalogVersion)
9
10 INSERT_UPDATE Product;code[unique=true];$supercategories;
manufacturerName;manufacturerAID;unit(code);variantType(code);
$catalogVersion;$approved
11 ;000010;000100;$manufacturer;$aid13;$unit;$variantType
12 ;000011;000100;$manufacturer;$aid15;$unit;$variantType

Abbreviations

Another way to shorten Impex files is to use abbreviations, you could use system
wide regex replacement for you Impex headers, for example out of the box there
is an header replacement for the classification header :
1 impex.header.replacement.1=C@(\\w+) ... @$1[system='\\$systemName',
version='\\$systemVersion',translator='de.hybris.platform.catalog
.jalo.classification.impex.ClassificationAttributeTranslator']

That’s the reason why during classification import you might encounter :
1 # Classification: Technical details (4593)
2 $feature1=@Motor diameter, 6752[$clAttrModifiers]; # Motor diameter
in millimeter (mm)

Document ID

Sometimes item references lookup method trough attributes is not enough and
you need to be able to have a reference to an object within an Impex file, that’s
when you use the & operator to create references :
1 INSERT_UPDATE Customer;groups(uid);uid[unique=true];name;
defaultPaymentAddress( &addrID )
2 ;customergroup;[email protected];Andrew;addr1
3
4 INSERT Address;&addrID;owner(Customer.uid);
5 ;addr1;[email protected];

Translators

For some attributes you need a special translator to import the object, the most
obvious example is for the media objects, in those cases you need to use a special
translator :
1 INSERT_UPDATE Media;code[unique=true];realfilename;@media[translator=
de.hybris.platform.impex.jalo.media.MediaDataTranslator];mime[
default='image/jpeg'];$catalogVersion
2 ;/img/low_pic/574-4346.jpg;574-4346.jpg;$siteResource/images/img/
low_pic/574-4346.jpg;

Have a look at the class de.hybris.platform.impex.jalo.


translators.AbstractSpecialValueTranslator and check all subclasses
to find out what translators are available out of the box
To insert map attributes, the default MapValueTranslator will be used, example
importing a saved query :
1 INSERT_UPDATE SavedQuery;code[unique=true];resulttype(code);query;
params(key,value(code))
2 ;savedQuery;Customer;SELECT {pk} FROM {Product} where {code} = ?code;
code->java.lang.String
Alternative pattern

When an item type relation is set to a basic item type such as ItemType for
example you could find the referenced item from multiple attributes, you can in
this case give the Impex attribute different options, below is an example with
the address owner type which is set to ItemType :
1 INSERT_UPDATE Address;lastname;owner( Principal.uid | AbstractOrder.
code )
2 ;Robert;[email protected]
3 ;Dupre;00000001

Distributed Impex

SAP Hybris V6 introduced a new concept of distributed Impex to share the


Impex import between nodes, it speeds up the execution of queries by splitting
them into batches that are executed in different nodes, this doesn’t need to be
configured since it’s the new default Impex engine. Importing data using the
new distributed mode consists of three steps :
• prepare then split
• single import execution
• finishing

Spring context
SAP Hybris is heavily using Spring, it offers developers the flexibility to
implement their work on top of the out of the box extensions. Spring offers
the ability to contain beans within different contexts, SAP Hybris provides
different application contexts :
• a global static application context shared by all tenants
– to configure it you need to configure an extra property within your
extension configuration extname.global-context=spring.xml
• a core application context for each tenant
– its parent the global application context
– to configure it within your extension
– use the convention resources/extname-spring.xml
– configure a different path extname.application-context=spring.xml
• a web application context for each web application
– configured inside the web.xml file of your extension (your extension
needs to have a web module defined within its extension.xml
configuration file)
– the listener org.springframework.web.context.ContextLoaderListener
configured within the web.xml automatically configured the core
application as parent of the web application context
– web application context can use core beans but cannot modify them
The order of loading Spring configuration is the same as in the build
process, so to override a Spring bean defined in extension A from
extension B, add a dependency in extension B for extension A
You can configure more than one Spring configuration file, simply
separate them with a coma, for example :
extname.application-context=spring1.xml,spring2.xml
To manually load a bean it is recommended to use
Registry.getApplicationContext() as this will first try to load it from a web
application context then from the core context and finally from the global
context.

Cronjobs
A cronjob is an automated task performed at a certain time (every day at 2 am
for example), or in fixed intervals (every hour for example), it can be used for:
• data backups
• Catalog synchronization
• importing or exporting data
A cronjob is made of :
• a job to do
• a trigger to start the job (not mandatory)
• a cronjob item which link the job and the trigger and configure the
environment the job will be performed in
To create a new Cronjob first you need to create a new item which extend the
Cronjob item type, we will create a cronjob that deactivate products that haven’t
been updated since a given time :
1 <typegroup name="hybhub">
2 <itemtype code="DeactivateOutdatedProductCronJob" extends="
CronJob">
3 <description>Job to deactivate out-dated products</
description>
4 <attributes>
5 <attribute type="java.util.Date" qualifier="minLastUpdate
">
6 <persistence type="property" />
7 </attribute>
8 </attributes>
9 </itemtype>
10 </typegroup>

Then we need to create the actual job that deactivate products based on the
minLastUpdate attribute :
1 package com.hybhub.job;
2

3 import de.hybris.platform.catalog.CatalogVersionService;
4 import de.hybris.platform.catalog.enums.ArticleApprovalStatus;
5 import de.hybris.platform.core.model.product.ProductModel;
6 import de.hybris.platform.cronjob.enums.CronJobResult;
7 import de.hybris.platform.cronjob.enums.CronJobStatus;
8 import de.hybris.platform.servicelayer.cronjob.AbstractJobPerformable
;
9 import de.hybris.platform.servicelayer.cronjob.PerformResult;
10 import de.hybris.platform.servicelayer.model.ModelService;
11 import de.hybris.platform.servicelayer.search.FlexibleSearchQuery;
12 import de.hybris.platform.servicelayer.search.FlexibleSearchService;
13

14 import java.util.List;
15

16 import javax.annotation.Resource;
17

18 import com.hybhub.model.DeactivateOutdatedProductCronJobModel;
19

20

21 public class DeactivateOutdatedProductJob extends


AbstractJobPerformable<DeactivateOutdatedProductCronJobModel>
22 {
23

24 @Resource
25 private FlexibleSearchService flexibleSearchService;
26

27 @Resource
28 private CatalogVersionService catalogVersionService;
29

30 @Resource
31 private ModelService modelService;
32

33 @Override
34 public PerformResult perform(final
DeactivateOutdatedProductCronJobModel cronjob)
35 {
36 final FlexibleSearchQuery fsq = new FlexibleSearchQuery("
SELECT {pk} FROM {Product} "
37 + "WHERE {modifiedtime} <= ?minLastUpdate " + " AND {
catalogVersion} = ?catalogVersion");
38

39 fsq.addQueryParameter("minLastUpdate", cronjob.
getMinLastUpdate());
40 fsq.addQueryParameter("catalogVersion", catalogVersionService
.getCatalogVersion("electronicsProductCatalog", "Staged")
);
41

42 final List<ProductModel> productsToUpdate =


flexibleSearchService.<ProductModel> search(fsq).
getResult();
43

44 productsToUpdate.stream().forEach((prd) -> {
45 prd.setApprovalStatus(ArticleApprovalStatus.UNAPPROVED);
46 modelService.save(prd);
47 });
48

49 return new PerformResult(CronJobResult.SUCCESS, CronJobStatus


.FINISHED);
50 }
51

52 }

You now need to create a Spring bean :


1 <bean id="deactivateOutdatedProductJob" class="com.hybhub.job.
DeactivateOutdatedProductJob"
2 parent="abstractJobPerformable" />

You need to update your system for SAP Hybris to find the new Job
Let’s create a cronjob from a Groovy script (You could do this from the HMC or
from an Impex query), we create a trigger but also we start the cron manually :
Don’t forget to switch the commit mode to on, if you execute this
more than once it will fail since cronjob codes needs to be unique !
1 import com.hybhub.model.DeactivateOutdatedProductCronJobModel
2 import de.hybris.platform.cronjob.model.JobModel
3 import de.hybris.platform.cronjob.model.TriggerModel
4

5 def modelService = spring.getBean("modelService")


6 def cronJobService = spring.getBean("cronJobService")
7 def flexibleSearchService = spring.getBean("flexibleSearchService")
8

9 JobModel job = new JobModel();


10 job.setCode("deactivateOutdatedProductJob")
11 job = flexibleSearchService.getModelByExample(job)
12

13 DeactivateOutdatedProductCronJobModel cron =
14 modelService.create(DeactivateOutdatedProductCronJobModel.class)
15

16 cron.setMinLastUpdate(new Date())
17 cron.setCode("deleteOutdatedProductsss")
18 cron.setJob(job)
19

20 modelService.save(cron)
21

22 TriggerModel trigger = modelService.create(TriggerModel.class)


23 trigger.setSecond(0)
24 trigger.setMinute(1)
25 trigger.setHour(0)
26 trigger.setDay(0)
27 trigger.setMonth(-1)
28 trigger.setYear(-1)
29 trigger.setCronJob(cron)
30

31 cronJobService.performCronJob(cron)

Be careful this will change the status of all your products under the
staged electronic product catalog !

Cluster
When you deploy SAP Hybris into production you would need to configure a
cluster of SAP Hybris nodes, a cluster offers :
• node specific configuration
• cron jobs / events for specific nodes
• session failover
• load balancing compatibility (load balancing needs to be done by a third
party component)
• choice of UDP (unicast or multicast) or TCP (Jgroup) for nodes
communication
All nodes are using the same database
Cache invalidation

Each SAP Hybris nodes have their own local cache, when one node update
an item in the cache it needs to tell the other nodes to invalidate the entry
in their local cache for consistency purpose, to do so the node would send a
request (TCP or UDP depends on your cluster configuration) so other nodes
would discard the item and reload it from the database the next time they need
to access that object.

Configuration

Node specific configuration can be done by using :


1 #cluster.<nodeid>.my.property=value
2 cluster.1.my.property=value

Nodes need to have a unique identifier, prior to SAP Hybris V6 you had to
manually configure an id for each node :
1 clustermode=true
2 cluster.id=0

This could make deployment more complex as you needed to provision a unique
identifier for each node, since SAP Hybris V6 you can activate auto discovery
mode, this will keep track of each nodes within the database :
1 clustermode=true
2 cluster.nodes.autodiscovery=true

Cluster configuration is available under your platform


project.properties file, if you want to change the out of the box
configuration remember to do it under your config local.properties
file
Chapter 9

PCM & price

Price calculation
SAP Hybris provides a flexible, scalable and configurable way to handle prices,
all price informations are contained with the PriceRow item type, a price row
has :
• a price
• a currency
• a unit factor
• a unit
• a minimum quantity
• a catalog version (not mandatory)
• a time frame (not mandatory)
• a customer or a groups of customers (not mandatory)
• a product or a group of products (not mandatory)
• a net flag (not mandatory)
Under SAP Hybris V6 the out of the box price factory
implementation is called Europe1PriceFactory this is a legacy name,
when the SAP Hybris team implemented their first price factory
they thought they would implement different price factories for each
regions which in fact was not needed, but they kept this legacy
name
The price factory is still using the deprecated jalo layer, therefore
within the next version Europe1PriceFactory might be migrated to
something like DefaultPriceFactoryService
To be selected by the price factory a price row needs (following the order of
execution) :

158
• match the customer / customer group or be empty
• match the product / product group
• within the date range if any configured
• quantity is equal or bigger than the minimum quantity if any configured
Currency conversion is done automatically if no price are defined
for the current currency, all conversions are done based on the base
currency and the conversion attribute of the targeted currency, have
a look at currencies from the HMC
After the price factory has loaded all matching prices it needs to select the final
one, ordered by highest priority :
• product and customer
• product group and customer
• product and customer group
• product group and customer group
• product and all customers
• product group and all customers
• all products and customer
• all products and customer group
• all products and all customers
When the price factory returns more than one price if they are more than one
match the PriceService will select the lowest one.

Taxes
Taxes are represented by tax rows, they define :
• an absolute flag
• a currency
• a date range
• a product tax group
• a product
• a product match qualifier
• a tax object
• a user tax group
• a user
• a user match qualifier
• a value
Tax rows are very similar to price rows, but unlike price rows you
accumulate them, for one product you could apply multiple taxes
unlike prices where you need to select only one instance
To match tax rows the Europe1PriceFactory will look for :
• customer / customer group or empty field
• product / product group or empty field
• date range

Discounts
Discounts are represented by discount rows, they define :
• an absolute flag
• a currency
• a date range
• a product discount group
• a product
• a product match qualifier
• a discount object
• a user discount group
• a user
• a user match qualifier
• a value
Discount rows are very similar to price rows, but unlike price rows you
accumulate them, for one product you could apply multiple discounts
unlike prices where you need to select only one instance
To match discount rows the Europe1PriceFactory will look for :
• customer / customer group or empty field
• product / product group or empty field
• date range

Media object
SAP Hybris supports media objects, a media item is a reference to any sort of
physical files stored on locally or remotely. It can be a picture, a text file, a
flash file, a zip archive and so on. A media is linked to only one file but a file
could be linked to more than one media. A media item is defined by :
• a location on the disk or remote location
• a unique identifier
• a catalog version
• a mime type
• a URL
• a folder
• a format
• a media container
• a location hash
• metadatas
• security rules
Out of the box Media type has multiple sub types for specialized objects like
Impex, Log and Email.
Medias are not localized, therefore to have a localized reference to
medias you need to declare an attribute this way : localized:Media
SAP Hybris offers out the box two MediaStorageStrategy :
• de.hybris.platform.media.storage.impl.LocalFileMediaStorageStrategy,
default out of the box strategy, files are stored along with Hybris under
the data directory
• de.hybris.platform.amazon.media.storage.S3MediaStorageStrategy, files
are stored within Amazon AWS S3 Buckets
Depending on the media storage strategy you are using you would need to select
the appropriate MediaURLStrategy, out of the box you have :
• de.hybris.platform.media.url.impl.LocalMediaWebURLStrategy
• de.hybris.platform.amazon.media.url.S3MediaURLStrategy

Media formats and Media container

Media formats help you to server the same image in different but for different
contexts, for example on the product listing page (PLP) you need to get a
small image of the products but on the product detail page (PDP) you need
a bigger image, all those formats are loaded within a media container which is
a container for multiple medias, inside a product media data object and you
can simply select the appropriate format on your front end. The out of the box
formats are :
1 <alias name="acceleratorImageFormatMapping" alias="imageFormatMapping
"/>
2 <bean id="acceleratorImageFormatMapping" parent="
defaultImageFormatMapping">
3 <property name="mapping">
4 <map>
5 <entry key="superZoom" value="1200Wx1200H"/>
6 <entry key="zoom" value="515Wx515H"/>
7 <entry key="store" value="365Wx246H"/>
8 <entry key="product" value="300Wx300H"/>
9 <entry key="thumbnail" value="96Wx96H"/>
10 <entry key="cartIcon" value="65Wx65H"/>
11 <entry key="styleSwatch" value="30Wx30H"/>
12 </map>
13 </property>
14 </bean>

Media contexts

SAP Hybris is a multi channel platform therefore you could be loading medias
in many different contexts from a mobile storefront to a print cockpit, therefore
you need to be able to adequate images format for each context, a media context
is a mapping container that would map a source format to a target format so
the proper image is loaded.

Secured media

by default media access is not secured.


1 media.default.secured=false

To secure all media turn configure it to true, if you need to secure only one
folder you can use :
1 media.folderName.secured=true

Permissions need to be configured for each media of the secured folder

Synchronization jobs
SAP Hybris has a concept of catalog and catalog versions, all item types which
are catalog aware (have an attribute of type CatalogVersion) can exist in
multiple catalogs. This gives you the flexibility to have a backstage where you
prepare your changes before you push it into production. Out of the box a
SAP Hybris system is configured with three type of catalogs, a content catalog
for CMS items, (paragraph, menu, pages…) medias, a product catalog and a
classification catalog.
Synchronizing catalogs means that you push the content of a catalog into
another, usually the Staged catalog into the Online catalog.
You can either run a synchronization as a cronjob or run manual synchronization
from the catalog, a CatalogVersionSyncJob is defined by :
• synchronization source and target (usually Staged to Online)
• create new elements flag
• remove missing elements flag
• synchronization languages
• root item types (item types to synchronize)
A catalog can have multiple versions. A Synchronization could merge
two Staged catalog into one Online catalog.
To create a new CatalogVersionSyncJob from an Impex query :
1 $productCatalog=productCatalog
2 $defaultCurrency=EUR
3 $languages=en
4 $defaultLanguage=en
5 $prices=europe1prices[translator=de.hybris.platform.europe1.jalo.
impex.Europe1PricesTranslator]
6 $stagedProduct=catalogVersion(catalog(id[default=$productCatalog]),
version[default='Staged'])[unique=true,default='$productCatalog:
Staged']
7 $onlineProduct=catalogVersion(catalog(id[default=$productCatalog]),
version[default='Online'])[unique=true,default='$productCatalog:
Online']
8
9 $sourceProductCV=sourceVersion(catalog(id[default=$productCatalog]),
version[default='Staged'])[unique=true,default='$productCatalog:
Staged']
10 $targetProductCV=targetVersion(catalog(id[default=$productCatalog]),
version[default='Online'])[unique=true,default='$productCatalog:
Online']
11
12 INSERT_UPDATE CatalogVersionSyncJob;code[unique=true];
$sourceProductCV;$targetProductCV;
13 ;sync productCatalog:Staged->Online;;;;

Workflow
SAP Hybris workflows help you modeling business processes like writing and
validating a product description in multiple languages, a workflow is defined by
:
• workflow template, it has a sequence of action templates
• workflow action template, define a step of a workflow, it produces an
option
• Option, possible result of an action it also defines the next step to follow
• workflow, an instance of a workflow template, created by making a copy
of the template
• workflow action, an instance of a workflow action template, created by
making a copy of the template
• decision, stores the option result of an action

• comment, a note left on a workflow action


• visible for principals, attached to the workflow template it gives users the
ability to create new workflows
A workflow action can have multiple statuses :
• pending, action not reached yet
• in progress
• completed
• disabled, deprecated
• ended through end of workflow
A workflow action template can be a :
• start action, meaning it’s the first step of a workflow
• normal step, meaning it’s neither the first or last step
• end step, meaning it ends the workflow
Start action are automatically marked as pending when the workflow
is started*
If no action are marked as start actions then all actions are set to
pending
If a workflow is ended without reaching all actions, then the status
of untouched actions is set to ended through end of workflow
SAP Hybris V6 has a fully functional workflow example under
productcockpitsampledata extension, have a look at
projectdata_workflow.impex.
Chapter 10

User Management

User rights
All groups and users within SAP Hybris are based on the principal item type,
this is the foundation of all users and groups (unique identifier). A user can be
either a Customer or an Employee :
• Customers are users designed to visit your store front and place orders.
• Employees are users designed to access the back office
There are three special principals within SAP Hybris that can’t be
modified or updated, the admin and anonymous users and the admin
group

Access rights

SAP Hybris has a permission framework that let you define your own access
rules to item types and attributes. An access right can be defined :
• globally for a user or user group
• for an item type
• for an instance of an an item type
• for an attribute
rights apply from the most general rules to most specific rules
Access right definitions could be either positive (granted) or negative
(denied)
If two rules collide, the most restrictive one would be applied, so if
one rule grants read right and another denies read right, the user
won’t have read right

165
To assign permissions you have two possibilities :
• Legacy Impex scripts that are only compatible with legacy permissions
(READ, CHANGE, CREATE, DELETE)
• PermissionManagementService is the new recommended way of managing
permissions, it allows you to create new permission types
Changing permissions takes effect immediately

Impex script

To define access rights using the legacy Impex script, you need to use
$START_USERRIGHTS and $END_USERRIGHTS to indicate that every
line in between those two statements are not Impex but user rights definition.
Example :
1 $START_USERRIGHTS
2 Type;UID;MemberOfGroups;Password;Target;read;change;create;delete;
change_perm
3 UserGroup;employeegroup;;
4 ;;;;Product;+;-;-;-;-
5 ;;;;CMSItem.name;+;-;-;-;-
6 $END_USERRIGHTS

Permission service

The out of the box


de.hybris.platform.servicelayer.security.permissions.PermissionManagementService
lets you :
• manage item type, item, attribute and global permissions
• create new permissions
Example how to get and set permissions :
1 import de.hybris.platform.servicelayer.security.permissions.
PermissionAssignment
2

3 def userService = spring.getBean("userService")


4 def pcs = spring.getBean("permissionCheckingService")
5 def typeService = spring.getBean("typeService")
6 def pms = spring.getBean("permissionManagementService")
7

8 def productmanager = userService.getUserForUID("productmanager")


9
10 println pcs.checkTypePermission("Product", productmanager, "read").
getCheckValue()
11

12 PermissionAssignment permission =
13 new PermissionAssignment("read", productmanager, true)
14 pms.addTypePermission(typeService.getComposedTypeForCode("Product")
15 , permission)
16

17 println pcs.checkTypePermission("Product", productmanager, "read").


getCheckValue()

Remember :
• de.hybris.platform.servicelayer.
security.permissions.PermissionCheckingService is used to check
permissions
• de.hybris.platform.servicelayer.
security.permissions.PermissionManagementService is used to configure
permissions
• de.hybris.platform.servicelayer.
security.permissions.PermissionCRUDService is used to check CRUD
operations (read, change, create, remove, change rights)

Search restrictions
Search restrictions are where clauses automatically added to flexible search
queries for specific users and item types. Restrictions do not apply for :
• SOLR search
• admin group users
• direct item type access though the model service
To deactivate search restriction use de.hybris.platform.search.
restriction.SearchRestrictionService.enableSearchRestrictions()
Since restrictions are linked to a session you have access to sessions attributes
within the restriction {user} = ?session.user. To create a restriction you can :
• use the service layer to create a restriction item
• execute an impex query

Service layer example

1 def typeService = spring.getBean("typeService")


2 def userService = spring.getBean("userService")
3 def modelService = spring.getBean("modelService")
4

5 def restrictedType = typeService.getComposedTypeForCode("Product");


6 def principal = userService.getUserForUID("anonymous");
7

8 def searchRestriction = modelService.create("SearchRestriction");


9 searchRestriction.setCode("OnlyPublicProduct");
10 searchRestriction.setActive(Boolean.TRUE);
11 searchRestriction.setQuery("{code} like '11%'");
12 searchRestriction.setRestrictedType(restrictedType);
13 searchRestriction.setPrincipal(principal);
14 searchRestriction.setGenerate(Boolean.TRUE);
15 modelService.save(searchRestriction);

Impex example

1 INSERT_UPDATE SearchRestriction;code[unique=true];name[lang=en];query
;principal(UID);restrictedType(code);active;generate
2 ;OnlyPublicProduct;Only Public Product;"{code} like '11%'";anonymous;
Product;true;true

B2B hierarchy
SAP Hybris B2B accelerator gives you the ability to manage company
organizations :
• Unit, basic block of an organization. A unit could represent a part
(location, department) or an entire organization
• Users, each user is attached to a unit and must have at least one of these
roles :
– administrator, can manage a unit
– manager, can access reports
– approver, can approve orders and define user’s monetary limit
– customer, place orders (automatically approved if under the approval
threshold)
• Cost center, assigned to units, orders are charged against a cost center
• Budget, assigned to units, if a unit exceed its budgets then orders are sent
to an approver
• Credit limit, credit limit are assigned by the merchant to a unit, it exceeds
the limit a manual approval is needed
When you run SAP Hybris with the B2B accelerator you have access to a new
panel under your account to manage your company organization directly from
the store front under My Company, to see this your user need to be B2B
administrator.
Chapter 11

Study tips

This covers suggestions and recommendations for SAP Hybris developers who
have been working on few implementations, have completed all trails from the
wiki and are starting to look at the certification proposed by SAP. If you have
never attempted any certification exams this will be stressful, all people at work
keep asking you when you finally pass that certification!

Study plan
Before you even sign up for the test you first need plan how you envision it :
1. I setup a V6 environment on my local
2. I learn how to use the Groovy console to quickly debug and understand
SAP Hybris
3. I configure my IDE with SAP Hybris and learn how to be comfortable
with the console
4. I pass the assessment exam
5. I study each chapter and play with SAP Hybris and all code fragments
provided
6. I pass the first mocked exam in real condition and list all unclear concepts
and wrong answers
7. I study again point listed from the first mocked exam
8. I pass the second mocked exam in real condition and list all unclear
concepts and wrong answers
9. I study again point listed from the second mocked exam
10. the days before the exam I randomly pick questions and check if I know
the answer

169
Play with SAP Hybris
To be ready for the exam you need to be able to create a new B2C
implementation, customize the initial data, create new pages and controllers
and customize the backoffice. While you are doing this you need not to only
follow the trails, try to remember things you would love to see within SAP
Hybris and implement then yourself (image compression, attribute automatic
translation, customized checkout…).
Most important is to learn how to tackle issues while developing, understand
why an impex file is not being imported or learn the difference between the Jalo
layer and service layer!

Identify your weakest point


After passing the first mock exam you should be able to know what part of the
exam will cause you troubles! Focus on that part if it’s Spring configuration
start from scratch and read the Spring documentation, once you are comfortable
with it come back to SAP Hybris.

Understand the Questions


Before you start answering a question look at all possible answers, you would
most likely be able to get context clues or understand more deeply the question.
Also do not waste time on a question you don’t understand even after reading
all possible answers! Simply move on and come back to it at the end of the
exam, often you might find help in other questions.
Although you might not immediately know the correct answer to a question,
if you can reduce the question from four answers down to two, your odds of
guessing the correct answer will be markedly improved.

Checking the answer


After passing a mocked exam the first step should be to look for the answer
within SAP Hybris, by looking for the answer yourself you would most likely
remember it next time you encounter a similar question. If you can’t find the
answer each question has a quick link to see the answer and each answer has a
quick link to navigate back to the question.
Chapter 12

Mock exam 1

Questions
Mock 1 - Question 1
What assessments are correct about modules and extensions ?
1. A module is a synonym of template
2. An extension is never used alone
3. A module includes a set of functionalities fulfilled by one or more
extensions
4. An extension holds source code and configuration files

Solution

Mock 1 - Question 2
What is a saved query ?
1. A query that has been cached by the service layer
2. A way of reusing a query from the flexible search service
3. A flexible search query saved inside the SavedQuery item type and reusable
from the HMC
4. There is no such query

Solution

171
Mock 1 - Question 3
Why do you need to execute setantenv.sh or setantenv.bat before calling the
build platform ?
1. To preload ant classes
2. To configure your PLATFORM_HOME environment variable
3. If you already have ant installed you do need to call this script
4. TO configure ant home and opts environment variable

Solution

Mock 1 - Question 4
Choose the correct definition for the bean scope singleton
1. One shared instance, which will be returned by all calls to getBean with
the given id
2. One shared instance per thread, which will be returned by all calls to
getBean with the given id
3. Independent instance resulting from each call to getBean
4. One shared instance per tenant, which will be returned by all calls to
getBean with the given id

Solution

Mock 1 - Question 5
What is the “batch=true” Impex header modifier ?
1. creates an individual import context for each value line
2. Allows modifying more than one item for a combination of all unique
attributes
3. inserts line by batches, default batch size is 20
4. There is no such header modifier

Solution
Mock 1 - Question 6
What are the steps in order to create a backoffice widget ?
1. create a widget view
2. create a widget model hook
3. create a widget definition
4. execute ant widgetGen

Solution

Mock 1 - Question 7
What is correct definition of the LTU eviction strategy ?
1. The oldest element would be deleted first
2. The youngest element would be deleted first
3. The most unused element would be deleted first
4. This is not a valid eviction strategy

Solution

Mock 1 - Question 8
Which of the following statements are not true regarding the use of inheritance
in SAP Hybris Item type definitions ?
1. All new item types must extend Object
2. All new item types must be declared within the Core extension
3. You can extend another item type only if it has been defined within the
same extension
4. Item types are not compatible with inheritance

Solution

Mock 1 - Question 9
Which one of the following design patterns has this as its primary goal ;
Provides a single, simplified interface to a complex system of
mutually dependent interacting objects ?
1. Strategy
2. Model View Controller
3. Service Layer
4. Facade

Solution

Mock 1 - Question 10
If you are performing a flexible search query as the user admin* which of the
following is true ?*
1. all restrictions on the search are ignored
2. you cannot perform a flexible search being admin
3. you will only see in the result for the admin catalog
4. at least one restriction must be configured or no search will be performed

Solution

Mock 1 - Question 11
When executing an Impex import, which of the following is true ?
1. you can only import one item type per Impex file
2. each line under header is a potential value line
3. you need to specify the location of the CSV value lines file
4. if you don’t specify a header the Impex framework will find a matching
item type

Solution

Mock 1 - Question 12
OAUTH2 is
1. a library built by SAP Hybris to handle authentification
2. a library built by Spring to handle authentification
3. an application protocol like HTTP but for authorization
4. an authorization protocol
Solution

Mock 1 - Question 13
To load a localized resource bundle, what service should you use ?
1. L10NService
2. I18NService
3. CommonI18NService
4. CommerceCommonI18NService

Solution

Mock 1 - Question 14
How can you activate the cluster mode ?
1. cluster mode is on by default
2. cluster mode is always on
3. configure clustermode=true
4. configure clustering=true

Solution

Mock 1 - Question 15
What are the logging framework shipped with Hybris ?
1. LOG4J
2. LOG4J2
3. LOG4J3
4. SLF4J

Solution
Mock 1 - Question 16
What happen when you run the following Impex script when the currency doesn’t
exist yet ?
1 UPDATE Currency;isocode[unique=true];conversion;digits;symbol
2 ;GBP;1;2;£

1. the import fails, log an error and move on to the next file
2. the import logs a warning and continue to resolve the remaining value
lines
3. the import logs a warning, creates a temporary file, and try to import it
later on
4. the import ignores non matching value lines when doing only UPDATE

Solution

Mock 1 - Question 17
Why is it considered bad practice to call directly
CartService.getSessionCart().getEntries().isEmpty() to test if a
customer already has a cart ?
1. this will create a cart if none is yet existing and the cart creation is
expensive
2. the customerCartService wrapper is preferred to the raw cart service
3. getSessionCart() is deprecated, use getInMemoryCart() instead
4. getEntries() could be null

Solution

Mock 1 - Question 18
What is the correct definition of the Spring MVC dispatcher servlet ?
1. receives incoming API requests and dispatch them to the right extension
2. process all incoming requests made to the root path
3. servlet responsible to find a matching controller and view to generate a
response
4. servlet responsible to load data from the database, load the JSP view and
delegate the request handling to a matching controller
Solution

Mock 1 - Question 19
What template do you use do create a new cockpit ?
1. ycockpit
2. cockpit
3. ybackoffice
4. backoffice

Solution

Mock 1 - Question 20
Which of the following cockpit import by convention files have a correct path and
name ?
1. cockpitextension/resources/cockpitextension-
admin/cscockpit/all/listViewContentBrowser_CatalogVersion.xml
2.
cockpitextension/resources/cockpitextension/cscockpit/cockpitgroup/listViewContentBrowser_CatalogVer
3. cockpitextension/resources/cockpitextension-
admin/cscockpit/cockpitgroup/listViewContentBrowser.xml
4. cockpitextension/resources/cockpitextension-
config/cscockpit/cockpitgroup/listViewContentBrowser_CatalogVersion.xml

Solution

Mock 1 - Question 21
Which methods are valid to create and save a new product item from the service
layer ?
1.
1 ModelService modelService = spring.getBean("modelService");
2 ProductModel prd = new ProductModel();
3 //Fill the product object with valid data
4 modelService.save(prd);
2.
1 ModelService modelService = spring.getBean("modelService");
2 ProductModel prd = modelService.create("Product");
3 //Fill the product object with valid data
4 modelService.save(prd);

3.
1 ModelService modelService = spring.getBean("modelService");
2 ProductService productService = spring.getBean("productService");
3 //Assuming we load a valid product
4 ProductModel prdTemplate = productService.getProductForCode("000001")
5 ProductModel prd = modelService.clone(prdTemplate)
6 //Set all unique data
7 modelService.save(prd);

Solution

Mock 1 - Question 22
What is the correct definition of the ant target updatesystem ?
1.type system definitions are modified to match the new type system definition
in the items.xml files, the update mechanism makes sure that all data that
existed in the system before the update is still accessible after the update
2.type system definitions are recreated to match the new type system definition
in the items.xml files, the update mechanism makes sure that all data that
existed in the system before the update is still accessible after the update
3.type system definitions are modified to match the new type system definition
in the items.xml files, the update mechanism makes sure that all data that
existed in the system are replaced by new data
4.type system definitions are modified to match the new type system definition
in the spring-items.xml files, the update mechanism makes sure that all data
that existed in the system before the update is still accessible after the update

Solution
Mock 1 - Question 23
How many currency items would be inserted from the following impex query,
assuming they don’t exist in SAP Hybris yet ?
1 INSERT_UPDATE Currency;isocode[unique=true];conversion;digits;symbol
2 ;DKK;1;2;DKK
3
4 INSERT Currency;isocode[unique=true];conversion;digits;symbol
5 ;DKK;7;2;DKK
6
7 INSERT_UPDATE Currency;isocode[unique=true];conversion;digits
8 ;VND;7;2;VND

1. none
2. one
3. two
4. three

Solution

Mock 1 - Question 24
Which of the following application contexts are valid ?
1. tenant service application context
2. tenant core application context
3. global web application context
4. hac web application context

Solution

Mock 1 - Question 25
Is this a valid item type definition ?
1 <itemtype code="DeactivateOutdatedProductCronJob">
2 <description>Job to deactivate out-dated products</description>
3 <attributes>
4 <attribute type="java.util.Date" qualifier="minLastUpdate">
5 <persistence type="memory" />
6 </attribute>
7 </attributes>
8 </itemtype>

1. no, a cronjob must extends the Cronjob item type


2. no, persistence can’t be of type memory
3. no, the jalo class definition is missing
4. yes

Solution

Mock 1 - Question 26
What does the ant target customize do ?
1. inject all properties into tomcat configuration
2. execute all call back scripts
3. copies all files from /config/customize folder to /bin folder recursively
4. customize the tomcat configuration folder from the config folder

Solution

Mock 1 - Question 27
What SQL query could be generated from the following flexible search query ?
1 select {pk} from {Product as prd}

1. SELECT prd.PK FROM products prd WHERE (prd.TypePkString IN


(?,?))
2. SELECT item_t0.PK FROM products item_t0 WHERE
(item_t0.TypePkString IN (?,?))
3. SELECT PK FROM products WHERE (TypePkString IN (?,?))
4. SELECT item_t0.PK FROM {products} item_t0 WHERE
(item_t0.TypePkString IN (?,?))

Solution
Mock 1 - Question 28
Which of the following item type attribute default value definition valid ?
1. java.lang.Boolean.FALSE
2. enumerationService().getEnumerationValue(“validEnumeration”,
“validValue”)
3. Boolean.FALSE
4. com.hybhub.core.ExistingClass.EXISTING_STATIC_STRING

Solution

Mock 1 - Question 29
The SAP Hybris out of the box model service is used to ?
1. refresh the status of a data object
2. lock a model object
3. remove a model object
4. create new item type definition

Solution

Mock 1 - Question 30
What statements about the backoffice application orchestrator are wrong ?
1. it’s already visible when you are logged as an admin
2. you use it to create and modify back office application
3. you use it to import new data
4. you need to press F4 to activate it

Solution

Mock 1 - Question 31
What is cached by SAP Hybris ?
1. result of flexible search queries
2. media images
3. item attributes
4. user sessions

Solution

Mock 1 - Question 32
Choose the correct definition of an interface based architecture ?
1. defines an application as a collection of components, in which API calls
between components are made through abstract interfaces, not concrete
classes
2. defines an application as a collection of components, in which API calls
between components are made through concrete classes, not abstract
interfaces
3. defines an application as a collection of static components, in which API
calls between components are made static references
4. defines an application as a collection of RESTFUL API entry points, calls
between components are made through HTTP requests

Solution

Mock 1 - Question 33
What steps are required in order to create a new SAP Hybris cron job ?
1. create a new trigger for the job
2. create a job implementation of JobPerformable
3. Update your system
4. create a new item that extends cronjob

Solution

Mock 1 - Question 34
How do you declare an attribute dynamic ?
1.
2.
3.
4.
Solution

Mock 1 - Question 35
How is Spring configured in SAP Hybris ?
1. Explicit configuration in XML
2. Explicit configuration in Java
3. Implicit bean discovery and automatic wiring
4. Explicit configuration in XML, implicit bean discovery and automatic
wiring

Solution

Mock 1 - Question 36
How could you enable single product catalog synchronization from the PCM ?
1. catalog synchronization cannot be done from the PCM, it’s meant to be
done by administrators only
2. configure expressUpdateCatalogVersions=catalog:version
3. each product can be synchronized individually out of the box
4. PCM is not for products

Solution

Mock 1 - Question 37
What is the default authorization framework for the OCC web services ?
1. spring-security
2. oauth 2.0
3. java-security
4. sso

Solution
Mock 1 - Question 38
In order to test a dao implementation what test should you write ?
1. @UnitTest
2. @DatabaseTest
3. @SqlTest
4. @IntegrationTest

Solution

Mock 1 - Question 39
How can you use environment variables in your Hybris configuration ?
1. from a call back scripts
2. using hybhub.config=$NAME assuming the env variable exists and is
named NAME
3. using hybhub.config= assuming the env variable exists and is name
y_hybhub_config
4. 3. using hybhub.config=? assuming the env variable exists and is name
hybhub_config

Solution

Mock 1 - Question 40
What statements are correct about he following impex ?
1 INSERT_UPDATE MediaFolder;qualifier[unique=true];path[unique=true]
2 ;images;images
3 ;email-body;email-body
4 ;email-attachments;email-attachments

1. only creates new MediaFolder


2. generates a unique database index from the qualifier and the path
3. contains 3 value lines
4. doesn’t use any macro

Solution
Mock 1 - Question 41
Which one of the following flexible correct is valid ?
1. select {name[de]} from {product}
2. select {name.de} from {product}
3. select {name}[de] from {product}
4. select {name} from {product},{lang} where {lang} = ‘de’

Solution

Mock 1 - Question 42
Choose the right definition for a payment capture ?
1. authorize an amount of money after it has been reserved
2. transfer money back for a given order
3. transfer money from after it has been authorized
4. lock an amount of money on the card’s holder account

Solution

Mock 1 - Question 43
Using the out of the box impex import convention, what files would be imported
during the update process (only create essential data checked) ?
1. extension/resources/impex/0_essentialdata.impex
2. extension/resources/impex/essentialdata_0.impex
3. extension/resources/impex/core/essentialdata_0.impex
4. extension/resources/impex/projectdata_users.impex

Solution

Mock 1 - Question 44
“A navigation technique for accessing a collection of available information by
narrowing down long lists of objects to a manageable size. The reduction is
achieved through attribute filters that can by applied in flexible combinations of
any order.” best describes ?
1. facet search
2. solr
3. category search
4. flexible search

Solution

Mock 1 - Question 45
How many catalog versions can be attached to a catalog ?
1. zero, a catalog defines its own version
2. one, the version can be shared across different catalogs, for example Online
3. two, catalogs have their own Staged and Online catalog versions
4. as many as needed, there are no limits at how many versions a catalog
can have

Solution

Mock 1 - Question 46
How many transactions would be created by the following Groovy script ?
1 def transaction = de.hybris.platform.tx.Transaction.current()
2

3 transaction.begin()
4

5 transaction.begin()
6 //Do something
7 transaction.commit()
8

9 transaction.begin()
10 //Do something
11 transaction.commit()
12

13 transaction.commit()

1. code execution will fail


2. one transaction would be created
3. two transactions would be created
4. three transaction would be created
Solution

Mock 1 - Question 47
What is the main entry servlet of Spring MVC application ?
1. SpringMvcServlet
2. DispatcherServlet
3. JaloServlet
4. RequestContextServlet

Solution

Mock 1 - Question 48
What statements are true about CMSItem and CMSRelation item types ?
1. their sub items are catalog version aware
2. it’s used by all tag components
3. every CMS types extend one or the other
4. they are defined under the core extension

Solution

Mock 1 - Question 49
How can you configure a new checkout flow ?
1. from an impex query
2. from a java implementation of
de.hybris.platform.acceleratorstorefrontcommons.checkout.CheckoutFLow
3. from a spring configuration
4. from JSP tag file

Solution
Mock 1 - Question 50
What application context is valid to create a new region cache for an item type
?
1. core tenant
2. master tenant
3. core static
4. global static

Solution

Mock 1 - Question 51
Choose the best definition for the following exception :
de.hybris.platform.servicelayer.exceptions.AmbiguousIdentifierException ?
1. the service layer can’t find any matching identifier
2. the service layer found more than one matching item and expected only
one
3. the service layer doesn’t know what attribute is used as the unique
identifier
4. the service layer doesn’t know the item type

Solution

Mock 1 - Question 52
What informations can you extract from a PK ?
1. type code
2. last modified time
3. created time
4. user who created the item

Solution
Mock 1 - Question 53
The Spring Integration Framework is used for ?
1. OCC webservices
2. Datahub
3. Hot Folder
4. Service Layer

Solution

Mock 1 - Question 54
Where can you specify an index for an item type ?
1. resources/extensionName-indexes.xml
2. resources/extensionName-items.xml
3. resources/extensionName-indices.xml
4. resources/database/index.sql

Solution

Mock 1 - Question 55
Choose the right definition for the order splitting service ?
1. split an order into sets of order entries, for each set a consignment is then
created
2. split an order into multiple orders, for each orders a consignment is then
created
3. split order entries into sets of order entries, for each set a consignment is
then created
4. split a consignment into sets of consignments, for each set a new
consignment is then created

Solution
Mock 1 - Question 56
When designing a new web service what HTTP header should you choose to
implement a create object endpoint ?
1. GET
2. PUT
3. CREATE
4. POST

Solution

Mock 1 - Question 57
What is the downside of product variants ?
1. none
2. you cannot have common attributes between variant objects without
changing the base product definition
3. products are virtual
4. all variant objects and the base product share the same unique code which
makes any search not trivial

Solution

Mock 1 - Question 58
How could you group solr attribute values in a single set to avoid excessive
number of values ?
1. use a group by statement
2. use a paginated solr search query
3. use a facet range
4. use a facet sort

Solution
Mock 1 - Question 59
Which of the following interceptors are valid ?
1. load
2. init
3. prepare
4. remove

Solution

Mock 1 - Question 60
What statements are true wrong about the build framework ?
1. it compiles extension in a pre-defined order
2. it generates and compiles sources from items.xml files
3. every ant targets compile the source files
4. it is runnable only from your platform folder

Solution

Mock 1 - Question 61
A Media can be ?
1. a image
2. a zip file
3. a flat file
4. a string

Solution

Mock 1 - Question 62
Which one of the following service is best suited to load a resource bundle for a
specific language ?
1. I18NService
2. CommonI18NService
3. CommerceCommonI18NService
4. L10NService

Solution

Mock 1 - Question 63
If I add the following search restriction for product and for user anonymous,
what will happen when anonymous users execute a product search ?
1 {name} is not null

1. this will fail, where is missing


2. this will replace any where clause for anonymous and product
3. this will be added to the where clause for anonymous and product
4. this will be added to the where clause for anonymous and product during
solr indexing

Solution

Mock 1 - Question 64
What happened when you execute the following Groovy script ?
1 import java.util.HashSet
2 import de.hybris.platform.core.model.user.UserGroupModel
3

4 def modelService = spring.getBean("modelService")


5

6 def group = modelService.create("userGroup")


7 group.setUid("newGroup")
8 modelService.save(group)
9 def groups = new HashSet<UserGroupModel>()
10 groups.add(group)
11

12

13 def customer = modelService.create("customer")


14 customer.setUid("newCustomer")
15 customer.setName("newCustomer")
16 customer.setGroups(groups)
17

18 modelService.save(customer)
1. a service layer exception is thrown
2. only the customer is created
3. only the user group is created
4. both the customer and the user group are created

Solution

Mock 1 - Question 65
What statements are true about the promotion engine ?
1. runs on the rule engine
2. runs on the jalo layer
3. uses rule aware object (RAO) actions
4. runs when the promotion strategy is called during cart calculation

Solution

Mock 1 - Question 66
How can you create a new socket for a custom backoffice widget ?
1. open your widget definition.xml file
2. use the HMC
3. run the widget wizard from OCC
4. create a new socket.zul file

Solution

Mock 1 - Question 67
What statements are true about Apache SOLR ?
1. SAP Hybris uses an embedded SOLR server
2. SOLR uses the same database as SAP Hybris
3. all products are cached inside SOLR
4. SOLR can have multiple index
Solution

Mock 1 - Question 68
Why would run the following flexible search query ?
1 select {pk} from {Product!}

1. you need only to load product subtype items


2. you need only to load product type items
3. you need only to load product variants
4. you need to tell SAP Hybris not to cache the result

Solution

Mock 1 - Question 69
What is the right way to create a localized string attribute ?
1.
1 <attribute qualifier="name" type="java.lang.String">
2 <persistence type="property" localized="true"/>
3 </attribute>

2.
1 <attribute qualifier="name" type="localized:String">
2 <persistence type="property"/>
3 </attribute>

3.
1 <attribute qualifier="name" type="localized:java.lang.String">
2 <persistence type="property" />
3 </attribute>

4.
1 <attribute qualifier="name" type="localized:java.lang.String">
2 </attribute>

Solution
Mock 1 - Question 70
What can you define permissions for (using the permission framework) ?
1. OCC access
2. item type
3. instance of an item type
4. attribute

Solution

Mock 1 - Question 71
What is the purpose of the following class ?
1 /*
2 * [y] hybris Platform
3 *
4 * Copyright (c) 2000-2016 SAP SE
5 * All rights reserved.
6 *
7 * This software is the confidential and proprietary information of
SAP
8 * Hybris ("Confidential Information"). You shall not disclose such
9 * Confidential Information and shall use it only in accordance with
the
10 * terms of the license agreement you entered into with SAP Hybris.
11 */
12 package com.hybhub.setup;
13

14 import ...
15

16 @SystemSetup(extension = HybhubhookConstants.EXTENSIONNAME)
17 public class HybhubHookSystemSetup extends AbstractSystemSetup
18 {
19

20 final static Logger LOG = LoggerFactory.getLogger(


HybhubHookSystemSetup.class);
21

22 @SystemSetupParameterMethod
23 @Override
24 public List<SystemSetupParameter> getInitializationOptions()
25 {
26 final List<SystemSetupParameter> params = new ArrayList<>();
27 params.add(createBooleanSystemSetupParameter("key", "Choice",
false));
28 return params;
29 }
30

31 @SystemSetup(type = Type.ALL, process = Process.ALL)


32 public void createEssentialData(final SystemSetupContext context)
33 {
34 final boolean choice = getBooleanSystemSetupParameter(context
, "choice");
35 if (choice)
36 {
37 //Do something
38 }
39 else
40 {
41 //Do something else
42 }
43 }
44

45 }

1. customize a HMC wizard


2. customize the impex import service
3. customize the update and initialization
4. customize the available import choices when running an update from the
HMC

Solution

Mock 1 - Question 72

Solution
Is this a valid impex import ?
1 INSERT_UPDATE Title;code
2 #% beforeEach: print(line[1]);
3 ;Doctor

1. yes
2. yes only if bean shell execution is activated
3. yes only if the title Doctor doesn’t exist yet
4. no

Mock 1 - Question 73
What is the recommended way of setting cluster ids ?
1. use cluster.node.autodiscovery=true
2. create a subnet and configure nodes to listen to the broadcast address
3. manually configure a unique id on each node
4. activate the Spring Cluster functionality

Solution

Mock 1 - Question 74
Which are valid steps of the ant build all target ?
1. Resolving extensions dependencies
2. Restart the application server
3. Delete all previously compiled classes
4. Generate sources for all extensions

Solution

Mock 1 - Question 75
Which statements are correct about widget definitions ?
1. widget definition is as simple as creating a Spring bean under your core
extension spring configuration
2. A widget needs to extend another widget id in order to be available
3. Each widget ids must be unique otherwise they wouldn’t be available
4. Widgets definition are located under
myextension/backoffice/resources/widgets/{widgetName}/definition.xml

Solution
Mock 1 - Question 76
What is the best way to create a new addon for your store front ?
1. generate a new extension from yempty
2. generate a new extension from yoccaddon
3. generate a new extension from yaddon
4. generate a new extension from addon

Solution

Mock 1 - Question 77
Is this a valid business process definition ?
1 <?xml version="1.0" encoding="utf-8"?>
2 <process>
3
4 <action id="action1" bean="action1">
5 <transition name="OK" to="success"/>
6 <transition name="NOK" to="action2"/>
7 </action>
8
9 <action id="action2" bean="action2">
10 <transition name="OK" to="error"/>
11 </action>
12
13 <end id="error" state="ERROR">All went wrong.</end>
14 <end id="success" state="SUCCEEDED">Order placed.</end>
15
16 </process>

1. yes
2. yes if you had a new action with start=true
3. yes if action1 implements StartProcess
4. no

Solution

Mock 1 - Question 78
What are the required steps to create a new CMSComponent ?
1. create an item that extends AbstractCMSComponent or one of its subtype
2. create an item that extends CMSItem or one of its subtype
3. a Spring MVC controller that extends AbstractCMSComponentController
4. a JSP (or other front end technology) to render the component

Solution

Mock 1 - Question 79
When should you run a full Apache SOLR indexation ?
1. when you restart the SOLR server
2. when you update a product
3. when you update prices
4. every day to recreate a clean index (not defragmented)

Solution

Mock 1 - Question 80
How many websites could you have per tenant ?
1. only one because orders and customers are tenant dependent
2. websites are not tenant aware
3. as many as you need
4. as many as you want if you are running a cluster

Solution

Solutions
Mock 1 - Solution 1
3,4 are correct.
A module is made of one or more extensions to provide a set of related
functionalities, like the WCMS module made from different extensions :
cms2lib, cmscockpit, cm2.
Solution

Mock 1 - Solution 2
3 is correct.
A saved query can be used from the HMC to search a given item type from a
customized and possibly parameterized flexible search query.

Solution

Mock 1 - Solution 3
2,4 are correct.
The setantenv scrips configure :
• PLATFORM_HOME
• ANT_OPTS
• ANT_HOME
• add ANT_HOME to your path

Solution

Mock 1 - Solution 4
1 is correct.
3 is the definition of prototype scope, 4 is correct only if you are inside different
tenant application context.

Solution

Mock 1 - Solution 5
2 is correct.
When you need to update more than one item from the same value line use the
batch mode.
Solution

Mock 1 - Solution 6
1,3 are correct.

Solution

Mock 1 - Solution 7
4 is correct.
The available eviction strategy are :
• LRU (Least Recently Used)
• LFU (Least Frequently Used)
• FIFO (First In First Out)

Solution

Mock 1 - Solution 8
**1,2,3,4*8 are correct.
1. All new item types extends GenericItem by default
2. Any extension with a core module defined could declare new item types
3. You can extend any item type from your extensions as long as you have
a dependency to the extension where the item type you inherit from is
defined
4. All item types extend one item type (except AbstractItemModel)

Solution

Mock 1 - Solution 9
4 is correct.
Solution

Mock 1 - Solution 10
1 is correct.

Solution

Mock 1 - Solution 11
2 is correct.
After a header all lines would be imported (unless they are empty, contain
comments or macro).

Solution

Mock 1 - Solution 12
4 is correct.
SAP Hybris OCC uses OAUTH2, the Java implementation of the secured
protocol is provided by Spring under Spring-security-oauth2.

Solution

Mock 1 - Solution 13
1 is correct.
• I18NService is to load Java Locale objects
• CommonI18NService is to load SAP Hybris internationalization objects
(CountryModel, LangageModel…)
• CommerceCommonI18NService is to load SAP Hybris internationalization
objects (CountryModel, LangageModel…) for the current base site

Solution
Mock 1 - Solution 14
3 is correct.

Solution

Mock 1 - Solution 15
2 is correct.
SLF4J is a simple logging facade for logging frameworks.

Solution

Mock 1 - Solution 16
3 is correct.
If there is no item that matches the values of all key attributes, the value line
cannot be resolved. The value line is dumped into a temporary file and the
ImpEx extension tries to resolve the value line later on.

Solution

Mock 1 - Solution 17
1 is correct.
Make sure your system does not create a new cart when the user does not
need it. This has massive impact to the system performance since for every
session a new entry in the Carts table is created. In SAP Hybris, if using
cartService.getSessionCart(), a new cart object is created implicitly if none is
yet existing for this session. You should always use cartService.hasSessionCart()
before.

Solution
Mock 1 - Solution 18
3 is correct.
A dispatcher servlet is the entry point of the Spring MVC framework, it loads
the right controller from its mapping, call the controller, use the view name
answered by the controller to load a view, and use the view and its model
(loaded inside the controller) to generate a a response.

Solution

Mock 1 - Solution 19
1 is correct.

Question

Mock 1 - Solution 20
4 is correct.
Remember extensionName/resources/extensionName-
config/userGroup/context_itemType.xml

Question

Mock 1 - Solution 21

Question
1,2,3 are correct

Mock 1 - Solution 22
1 is correct.
Question

Mock 1 - Solution 23
2 is correct.
1 INSERT Currency;isocode[unique=true];conversion;digits
2 ;DKK;7;2;DKK

would fail since because it’s conflicting with an existing item


(de.hybris.platform.impex.jalo.imp.ItemConflictException)

Question

Mock 1 - Solution 24
2,4 are correct.

Question

Mock 1 - Solution 25

Question
2 is correct.
To create a new SAP Hybris cronjob you need to extend the cronjob item type,
but it doesn’t make the item definition invalid.

Mock 1 - Solution 26
3 is correct.

Question
Mock 1 - Solution 27
2 is correct.

Question

Mock 1 - Solution 28
1,3,4 are correct.
The correct way to load enumeration default values is to call the enumeration
manager using em().

Question

Mock 1 - Solution 29
2,3 are correct.
have a look at de.hybris.platform.servicelayer.model.ModelService.

Question

Mock 1 - Solution 30
1,3 are correct.

Question

Mock 1 - Solution 31
1,3 are correct.

Question
Mock 1 - Solution 32
1 is correct.

Question

Mock 1 - Solution 33
2,3,4 are correct.

Question

Mock 1 - Solution 34
2 is correct.

Question

Mock 1 - Solution 35
4 is correct.

Question

Mock 1 - Solution 36

Question
2 is correct.

Mock 1 - Solution 37
2 is correct.
Question

Mock 1 - Solution 38
4 is correct.

Question

Mock 1 - Solution 39
3 is correct.

Question

Mock 1 - Solution 40
3,4 are correct.

Question

Mock 1 - Solution 41
1 is correct.

Question

Mock 1 - Solution 42
3 is correct.
Capture, is the action of transferring money into the merchant account after it
has been authorized.
Question

Mock 1 - Solution 43
2 is correct.
1,2 don’t respect the convent (**essentialdata*.impex**) 3 project data are not
being imported in this scenario.

Question

Mock 1 - Solution 44
1 is correct.

Question

Mock 1 - Solution 45
4 is correct.

Question

Mock 1 - Solution 46
2 is correct.
Remember that only one transaction per thread can be created.

Question

Mock 1 - Solution 47
2 is correct.
Question

Mock 1 - Solution 48
1,3 are correct.

Question

Mock 1 - Solution 49
3 is correct.

Question

Mock 1 - Solution 50
4 is correct.

Question

Mock 1 - Solution 51
2 is correct.

Question

Mock 1 - Solution 52
1 is correct.

Question
Mock 1 - Solution 53
3 is correct.

Question

Mock 1 - Solution 54
2 is correct.

Question

Mock 1 - Solution 55
1 is correct.

Question

Mock 1 - Solution 56
4 is correct.

Question

Mock 1 - Solution 57
2 is correct.
Product variants have an attribute baseProduct of type Product, so any to add
shared attributes between variants object you need to update the base product
definition.

Question
Mock 1 - Solution 58
3 is correct.

Question

Mock 1 - Solution 59
1,2,3,4 are correct.

Question

Mock 1 - Solution 60
1,3,4 are correct.

Question

Mock 1 - Solution 61
1,2,3 are correct.

Question

Mock 1 - Solution 62
4 is correct.

Question

Mock 1 - Solution 63
3 is correct.
Question

Mock 1 - Solution 64
4 is correct.

Question

Mock 1 - Solution 65
1,3 are correct.

Question

Mock 1 - Solution 66
1 is correct.

Question

Mock 1 - Solution 67
4 is correct.
1 is wrong since SAP Hybris V6 Apache SOLR is running in its own process.

Question

Mock 1 - Solution 68
2 is correct.

Question
Mock 1 - Solution 69
3 is correct.
4 is wrong, persistence is mandatory.

Question

Mock 1 - Solution 70
2,3,4 are correct.

Question

Mock 1 - Solution 71
3 is correct.

Question

Mock 1 - Solution 72
4 is correct.
A bean shell script can be executed from an impex script but an update need a
unique identifier.

Question

Mock 1 - Solution 73
1 is correct.

Question
Mock 1 - Solution 74
1,2,3 are correct.

Question

Mock 1 - Solution 75
3,4 are correct.

Question

Mock 1 - Solution 76
3 is correct.

Question

Mock 1 - Solution 77
4 is correct.
Missing start=“startAction” name=“processName”
processClass=“Process.Class”

Question

Mock 1 - Solution 78
1,4 are correct.
You don’t have to provide a controller, if none is provided the
DefaultCMSComponentController is used.

Question
Mock 1 - Solution 79
4 is correct.

Question

Mock 1 - Solution 80
3 is correct.

Question
Chapter 13

Mock exam 2

Questions
Mock 2 - Question 1
What describe best the JALO layer ?
1. means Jakarta Logic
2. mix data and business logic
3. it’s a piece of the service layer
4. JALO classes are generated during runtime

Solution

Mock 2 - Question 2
For the following query to be imported successfully what changes need to be done
?
1 $productCatalog=apparelProductCatalog
2 $productCatalogName=Apparel Product Catalog
3
4 INSERT_UPDATE ApparelProduct;code;$catalogVersion;unit(code);
supercategories(code,$catalogVersion)
5 ;300441142;;pieces;Blue Tomato,caps

1. add a macro for catalog version


2. change the attribute header INSERT_UPDATE to INSERT_UNIQUE
3. mark code with [unique=true]

217
4. use the type Product instead of ApparelProduct

Solution

Mock 2 - Question 3
**Choose the correct file to localize HMC entries in English (extension’s name
is hybhubcore)?*
1. hybhubcore/resources/localization/hybhubcore-locales_en.properties
2. hybhubcore/resources/localization/hmc-locales_en.properties
3. hybhubcore/hmc/localization/hybhubcore-locales_en.properties
4. hybhubcore/resources/localization/english/hybhubcore.properties

Solution

Mock 2 - Question 4
Select the right definition for the tenant concept ?
1. a single SAP Hybris installation with multiple localextensions.xml
2. a clustered SAP Hybris installation with one database
3. a single SAP Hybris installation with distinct sets of data
4. a single SAP Hybris installation with a specific database for each store

Solution

Mock 2 - Question 5
When do you use cluster aware events ?
1. when you run a cluster all events need to be cluster aware
2. since SAP Hybris V6 all events are cluster aware
3. when you need to run an event from a specific node
4. when you need to broadcast an event to all nodes

Solution
Mock 2 - Question 6
Why does the rule engine (used by the promotion engine) include a versioning
and archiving mechanism ?
1. to keep an history of all promotions that ever existed on the system
2. to have a consistent representation of the applied rules when promotions
were applied
3. to be able to work on different time zone
4. all item types in SAP Hybris are archived and versioned

Solution

Mock 2 - Question 7
What is wrong with the following item type definition ?
1 <itemtype code="Subscription" extends="GenericItem">
2 <attributes>
3 <attribute type="java.lang.String" qualifier="code">
4 <persistence type="property" />
5 <modifiers unique="true"/>
6 </attribute>
7 </attributes>
8 <indexes>
9 <index name="codeIdx">
10 <key attribute="code"/>
11 </index>
12 </indexes>
13 </itemtype>

1. missing a Jalo class definition


2. an index needs to be on at least two attributes
3. GenericItem is not a valid item
4. missing deployment data

Solution

Mock 2 - Question 8
Out of the box, what CMS items are used to build the top navigation menu ?
1. NavigationBarComponent
2. TopMenuNavigationComponent
3. CMSNavigationNode
4. CMSLinkComponent

Solution

Mock 2 - Question 9
What steps you need to have to fulfill in order to create a new cronjob ?
1. create a new cron job expression from Spring
2. implement a job
3. create a new item type extending CronJob
4. add the new cronjob in your local.properties

Solution

Mock 2 - Question 10
What statements are false about catalogs synchronization ?
1. only existing items can be updated
2. no items can be deleted
3. all item types are being synchronized
4. the same catalog can a target and a source

Solution

Mock 2 - Question 11
Cached data are removed from the cache when ?
1. the cache is full
2. a cache invalidation notification is received from another node
3. an item is created
4. an item is removed

Solution
Mock 2 - Question 12
What statements are true about classification ?
1. classification is horizontal unlike categorization which is vertical
2. a product can be classified by only one classification attribute
3. classification is not being used by SAP Hybris because its model type
definition is flexible
4. classification is not compatible with SOLR

Solution

Mock 2 - Question 13
What can you do from an addon ?
1. add front end files (JSP, HTML, CSS and Javascript)
2. generate or customize the data model
3. declare new Spring Services or Facades or customize existing
4. declare new Controllers or customize existing

Solution

Mock 2 - Question 14
What configuration file has the highest priority ?
1. project.properties from the platform extension
2. advanced.properties from the platform extension
3. local.properties from the config extension
4. local.properties from the custom extension

Solution

Mock 2 - Question 15
When you create the following item type A what classes are being generated ?
1 <itemtype code="A" extends="ItemB" generate="false">
2 <attributes>
3 <attribute type="java.lang.String" qualifier="code">
4 <persistence type="property" />
5 <modifiers unique="true"/>
6 </attribute>
7 </attributes>
8 </itemtype>

1. A.java
2. GeneratedA.java
3. AJalo.java
4. AModel.java

Solution

Mock 2 - Question 16
When configuring the Apache SOLR indexer mode what does DIRECT means
?
1. access the embedded Apache SOLR server
2. send request to Apache SOLR using its REST API
3. all index operations would be made directly on the index
4. all index operations would be made on a temporary index before indexes
are switch

Solution

Mock 2 - Question 17
Is it possible for two tenants to use different extensions ?
1. yes using two different localextensions.xml, one for each tenant
2. yes using allowed.extensions and forbidden.extensions inside a tenant
specific configuration file
3. yes using .allowed.extensions and .forbidden.extensions inside your
configuration
4. no, SAP Hybris is not compatible with this

Solution
Mock 2 - Question 18
How do you install a new addon ?
1. add the addon inside your localextensions.xml
2. add the addon under external-dependencies.xml
3. use the ant target addoninstall
4. use the ant target syncaddons

Solution

Mock 2 - Question 19
Is this a valid Flexible Search Query ?
1 select {p.description[fr]:o} from {Product as p} where {p:pk} in
2 ( {{ select {p:pk} from {product as p} where {p:code} like '%0%' }} )

1. no
2. yes if we delete :o
3. yes if we delete the whole where statement
4. yes

Solution

Mock 2 - Question 20
Out of the box how can you access the assisted service module functionalities ?
1. from the targeted storefront add a request parameter asm equal true
2. from the backoffice open the asm perspective
3. go to the /asmcockpit
4. go to the /cscockpit

Solution

Mock 2 - Question 21
How can you initialize SAP Hybris ?
1. using ant initialize
2. from the HAC
3. from the HMC
4. from the backoffice

Solution

Mock 2 - Question 22
What is highest B2B organization block ?
1. company
2. unit
3. division
4. region

Solution

Mock 2 - Question 23
In order to force a product to be listed on top of a give category, what out of the
box features should you use ?
1. boost rules
2. hero rules
3. hero products
4. top products

Solution

Mock 2 - Question 24
What payment steps is described by the following definition ?
1 Transfer back money to a customer account, the transfer not being
associated with any order or previous transactions.

1. capture
2. stand alone refund
3. capture
4. refund
Solution

Mock 2 - Question 25
The BTG module is used to ?
1. personalize a web applications based on customers
2. business to groups
3. provides a upgraded version of the CMS cockpit
4. add business targets accessible from the backoffice

Solution

Mock 2 - Question 26
What ant target should you use to start working on a new B2C implementation
?
1. ant installer -r b2c_acc
2. ant extgen
3. ant modulegen
4. ant accelerator

Solution

Mock 2 - Question 27
What Spring context has the larger scope ?
1. web context
2. core context
3. shared context
4. international context

Solution
Mock 2 - Question 28
During an Impex import what will happen when the import process can’t find a
reference to an item type ?
1. import process will fail and move onto the next file
2. the value line would be ignored
3. the value line would be saved and a new attempt would be made
4. the value line would be saved and attached to an error log entry

Solution

Mock 2 - Question 29
When loading available prices what is the price factory trying to match ?
1. customer / customer group
2. product / product group
3. date range if any configured
4. promotion / promotion group

Solution

Mock 2 - Question 30
What is the problem with the following business process action ?
1 package com.hybhub.core.process.action;
2

3 import de.hybris.platform.core.model.order.OrderModel;
4 import de.hybris.platform.orderprocessing.model.OrderProcessModel;
5 import de.hybris.platform.processengine.action.
AbstractSimpleDecisionAction;
6 import de.hybris.platform.servicelayer.model.ModelService;
7 import de.hybris.platform.task.RetryLaterException;
8

9 import javax.annotation.Resource;
10

11

12 public class HybhubSimpleAction extends AbstractSimpleDecisionAction<


OrderProcessModel>
13 {
14
15 @Resource
16 private ModelService modelService;
17

18 @Override
19 public Transition executeAction(final OrderProcessModel
orderProcess) throws RetryLaterException, Exception
20 {
21 OrderModel order = orderProcess.getOrder();
22

23 if(order!= null){
24 order.setNet(Boolean.TRUE);
25 modelService.save(order);
26 return Transition.OK;
27 }
28

29 return null;
30 }
31

32 }

1. it doesn’t always return a transition


2. it has not setter for the modelService attribute
3. it should implement Action
4. the package is wrong

Solution

Mock 2 - Question 31
What is true about the DefaultCMSComponentController* controller ?*
1. it will inject all attributes into the model
2. it will inject all front-end attributes (non system) into the model
3. it is used by default if no specific controller are implemented
4. it should be avoided

Solution

Mock 2 - Question 32
What is true about the following log extracted from the build process ?
1 [echo] catalog->(validation,commons) 6.0.0.0-SNAPSHOT [p*cib]

1. the catalog extension was automatically required


2. the catalog extension has a core module
3. the catalog extension is deprecated
4. the catalog extension is a platform extension

Solution

Mock 2 - Question 33
Choose the correct user rights definition to complete the following import query.
1 $START_USERRIGHTS
2 Type;UID;MemberOfGroups;Password;Target;read;change;create;delete;
change_perm
3 UserGroup;employeegroup;;
4 <Choose the right answer to complete this>
5 $END_USERRIGHTS

1. ;;;;Media;true+;false;false;false;false
2. ;;;;Media;1;0;0;0;0
3. ;;;;Media;+;-;-;-;-
4. ;;;;Media;granted;denied;denied;denied;denied

Solution

Mock 2 - Question 34
Which of the following components are deprecated ?
1. cockpit framework
2. Jalo layer
3. task engine
4. service layer

Solution
Mock 2 - Question 35
What is the correct way of configuring a new logger for the package
com.hybhub.hybhubaddon* ?*
1.
1 log4j.logger.com.hybhub.hybhubaddon = info

2.
1 log4j.logger.hybhub.name = com.hybhub.hybhubaddon
2 log4j.logger.hybhub.level = info
3 log4j.logger.hybhub.appenderRef.stdout.ref = STDOUT

3.
1 log4j2.logger.hybhub.name = com.hybhub.hybhubaddon
2 log4j2.logger.hybhub.level = info
3 log4j2.logger.hybhub.appenderRef.stdout.ref = STDOUT

4.
1 log4j2.logger.com.hybhub.hybhubaddon = info
2 log4j2.logger.com.hybhub.hybhubaddon = STDOUT

Solution

Mock 2 - Question 36
The OCC webservices are ?
1. restful API
2. restless API
3. soap API
4. oAuth API

Solution

Mock 2 - Question 37
What statements are wrong about converters ?
1. they all have the same bean parent abstractPopulatingConverter
2. they contain a list of attributes to convert
3. they contain a list a populators to call
4. they are un-aware of the object type they are converting

Solution

Mock 2 - Question 38
What is wrong with the following extensioninfo.xml* file ?*
1 <extensioninfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="extensioninfo.xsd">
2 <extension abstractclassprefix="Generated" classprefix="
HybhubFacades" name="hybhubfacades">
3 <requires-extension name="hybhubfacades"/>
4 <requires-extension name="hybhubcore"/>
5 <coremodule generated="true" manager="de.hybris.platform.jalo
.extension.GenericManager" packageroot="com.hybhub.
facades"/>
6 </extension>
7 </extensioninfo>

1. missing web module declaration


2. missing core module declaration
3. missing hmc module declaration
4. dependency issue

Solution

Mock 2 - Question 39
Is the following dynamic attribute handler correct ?
1 package com.hybhub.core.model.dynamic;
2

3 import de.hybris.platform.core.model.product.ProductModel;
4 import de.hybris.platform.servicelayer.model.attribute.
DynamicAttributeHandler;
5

6 public class HybhubDynamicHandler implements DynamicAttributeHandler<


String, ProductModel>
7 {
8
9 @Override
10 public String get(ProductModel product)
11 {
12 return product.getCode() + " - " + product.getDescription();
13 }
14

15 }

1. no, it must extends ServiceLayerItems


2. no, it must also implement a setter
3. no, it must be in a different package
4. yes

Solution

Mock 2 - Question 40
What statements are true about collections under item type definitions ?
1. a collection is comma-separated list of PKs
2. collections are preferred over relations
3. at runtime collections are loaded into a collection of objects
4. collections can store as many objects as needed

Solution

Mock 2 - Question 41
Which of the following definition is the correct one for unit tests ?
1. requires access to the database and need a running SAP Hybris
2. requires access to the database and don’t need a running SAP Hybris
3. does not require access to the database and don’t need a running SAP
Hybris
4. require access to the database and starts a transaction for each test

Solution
Mock 2 - Question 42
What is the following Spring configuration doing ?
1 <context:annotation-config/>
2 <context:component-scan
3 base-package="...,..."
4 scope-resolver="..."/>

1. add a new XML Spring configuration


2. load all detected components from the given packages
3. create a new bean scope
4. configure a request filter

Solution

Mock 2 - Question 43
*When you synchronize a Media object from a Staged to an Online catalog what
happens to the media file ?
1. the Media file is referenced by the Online and Staged Media
2. the Media file is copied to the Online data folder and referenced by the
Online Media
3. the Media file is moved to a shared folder and referenced by both Media
4. the Media file is embedded inside the file attribute and synchronize like
all other attributes

Solution

Mock 2 - Question 44
Select the right definition for the facade layer.
1. builds a complex object using simple objects and using a step by step
approach
2. separates application’s concerns
3. hides the complexities of the system and provides a simplified interface to
the client
4. add new functionality to an existing object without altering its structure
Solution

Mock 2 - Question 45
Select the existing Impex header mode.
1. INSERTED
2. UPDATE_INSERT
3. REMOVE
4. DELETE

Solution

Mock 2 - Question 46
How could you configure a new hot folder ?
1. from the HAC
2. from the HMC
3. from the import cockpit
4. from a Spring config file

Solution

Mock 2 - Question 47
How do you create a new interceptor ?
1. declare it along with the item type definition
2. provide an implementation of one of Interceptor interface
3. run a system update
4. add a Spring bean mapping the item type and the Interceptor
implementation

Solution
Mock 2 - Question 48
A checkout step has ?
1. checkoutGroup reference
2. checkoutStepValidator reference
3. transitions map
4. progressBarId string

Solution

Mock 2 - Question 49
What are are valid legacy cockpit areas ?
1. navigation
2. item
3. browser
4. editor

Solution

Mock 2 - Question 50
When running an initialization on one tenant SAP Hybris will ?
1. delete all tables
2. delete all known tables
3. delete all known tables starting with the tenant table prefix
4. delete and recreate the database

Solution

Mock 2 - Question 51
When creating a new item how do you generate a new primary key ?
1. using java.util.UUID.randomUUID()
2. using the primaryKeyService
3. primary keys creation is automatically handled by the database
4. primary keys creation is automatically handled by the service layer
Solution

Mock 2 - Question 52
How could you declare configure an attribute to be encrypted ?
1.
1 <attribute qualifier="sensible" autocreate="true" type="java.lang.
String">
2 <persistence type="property"/>
3 <modifiers encrypted="true"/>
4 </attribute>

2.
1 <attribute qualifier="sensible" autocreate="true" type="encrypted:
java.lang.String">
2 <persistence type="property"/>
3 </attribute>

3.
1 <attribute qualifier="sensible" autocreate="true" type="java.lang.
String">
2 <persistence type="property" encrypted="true"/>
3 </attribute>

4.
1 <attribute qualifier="sensible" autocreate="true" type="java.lang.
String">
2 <modifiers type="property" encrypted="true"/>
3 </attribute>

Solution

Mock 2 - Question 53
Which item types exist ?
1. collectiontype
2. enumtype
3. atomictype
4. listtype
Solution

Mock 2 - Question 54
A customer segment could be executed in ?
1. optimized processing
2. full processing
3. jalo processing
4. complete processing

Solution

Mock 2 - Question 55
Why a Spring MCV controller needs to return a String ?
1. to return it as an HTML page
2. to load a view
3. to load a servlet
4. to load a model

Solution

Mock 2 - Question 56
What features are available through the Order Management Module (formally
OMS) ?
1. order splitting
2. payment
3. sourcing
4. promotion engine

Solution
Mock 2 - Question 57
Why do you need to define stop words for for your search configuration ?
1. to ignore configured words while searching
2. to boost configured words while searching
3. to stop the query after a configured word
4. to split the query in two queries

Solution

Mock 2 - Question 58
What are the two main components of the rule engine ?
1. rule processor
2. rule matcher
3. rule executor
4. rule builder

Solution

Mock 2 - Question 59
How could you improve the following code (groovy) ?
1 import de.hybris.platform.processengine.enums.ProcessState
2

3 def businessProcessService = spring.getBean("businessProcessService")


4 def modelService = spring.getBean("modelService")
5

6 def process = businessProcessService.createProcess(UUID.randomUUID().


toString(), "myProcess")
7 modelService.save(process)
8

9 businessProcessService.startProcess(process)
10

11 modelService.refresh(process)
12 if(ProcessState.SUCCEEDED != process.getProcessState()){
13 businessProcessService.startProcess(process)
14 }
1. use the method T startProcess(String arg0, String arg1); to create a
process
2. delete the second call trying to start the business process
3. delete the useless call to save
4. generate a unique identifier for the business process

Solution

Mock 2 - Question 60
What statements are true about the following table (SQL DDL for HSQL) ?
1 CREATE CACHED TABLE b2bbudgetslp
2 (
3 ITEMPK BIGINT,
4 ITEMTYPEPK BIGINT,
5 LANGPK BIGINT,
6 p_name NVARCHAR(255),
7 PRIMARY KEY (ITEMPK, LANGPK)
8 );

1. table prefix is b2b


2. the item b2bbudgets has only one attribute
3. contains localized attributes for b2bbudgets item
4. it has 4 primary keys

Solution

Mock 2 - Question 61
Why would you use classification ?
1. to optimize Apache SOLR requests
2. to have dynamic product features
3. to speed up search
4. to unify product and category attributes

Solution
Mock 2 - Question 62
Which facet search configuration attributes give you the ability to redirect a user
for a specific search request ?
1. stopwords
2. keywords
3. redirectwords
4. matchwords

Solution

Mock 2 - Question 63
What statements are wrong about extensions ?
1. they have to be inside the bin folder
2. they need to have a dependency to yempty
3. they can written using Groovy
4. they are always automatically loaded

Solution

Mock 2 - Question 64
What statements are true about the SAP Hybris server ?
1. based on Apache Tomcat
2. good for production
3. compatible with EJB
4. can be started from the command line

Solution

Mock 2 - Question 65
When you run an impex import query from the HAC with the default configuration
what statements are true ?
1. you are running distributed impexes
2. you are using the service layer
3. you are using the jalo layer
4. import relaxed is activated

Solution

Mock 2 - Question 66
Which of the following would be good uses for a SAP Hybris CronJob ?
1. synchronizing the stock level with an external warehouse once per day
2. notify the System Administrator when the peak load on the server passes
a critical point
3. perform an inventory once per week at midnight
4. any task that isn’t database related, cronjobs are designed to perform
operating System tasks, not database system tasks

Solution

Mock 2 - Question 67
Content slots for page template are ?
1. place holder for CMS component
2. place holder for JSP tags
3. shared across all pages using the page template
4. configured on the JSP view page

Solution

Mock 2 - Question 68
Which bean would be loaded from getBean(“bean”)* ?*
1 <bean name="stringBean" class="java.lang.String" >
2 <constructor-arg><value>my String Name</value></constructor-arg>
3 </bean>
4
5 <bean id="stringBean" class="java.lang.String" >
6 <constructor-arg><value>my String ID</value></constructor-arg>
7 </bean>
8
9 <alias name="stringBean" alias="bean" />

1. my String Name
2. my String ID
3. a new String
4. none

Solution

Mock 2 - Question 69
Is it possible to add new enumeration values by runtime ?
1. no
2. yes if you are using JRebel
3. yes if the enumeration is dynamic
4. yes if the enumeration is a subtype of the HybrisEnumValue class

Solution

Mock 2 - Question 70
What a POS is ?
1. a warehouse
2. a physical store
3. a web store
4. a geolocalization service

Solution

Mock 2 - Question 71
What statements are wrong about Backoffice widgets ?
1. widget can extend each other
2. widget ids must be unique or the compilation fails
3. views are implemented using JSP tags
4. widgets can have parameters
Solution

Mock 2 - Question 72
When writing unit tests how should you simulate pojo dependencies to external
services, facades… ?
1. the test class should extend HybrisUnitTests
2. the test class should extend ServicelayerTest
3. use Mockito to stub dependencies
4. wrap all tests inside a transaction

Solution

Mock 2 - Question 73
What is the notification framework used for ?
1. notify cockpit users
2. notify customers
3. notify administrators
4. facade for the event service

Solution

Mock 2 - Question 74
What statements are true about stock levels ?
1. the stock service can check stock levels across multiple warehouses
2. a single warehouse can contain multiple stock levels for the same product
3. a base store is attached to a single warehouse
4. a product can be sold even if it has no stock

Solution
Mock 2 - Question 75
The CS cockpit was designed for ?
1. customer segment management
2. order life cycles management
3. css rendering management
4. customer security management

Solution

Mock 2 - Question 76
SAP Hybris semi-session failover mechanism allows to ?
1. automatically redirected users to the login page of a new node when on
node goes down
2. to transfer all sessions of the failing node to other available nodes without
loss of data
3. to always have all sessions replicated on every nodes
4. to automatically redirect users to a temporary page

Solution

Mock 2 - Question 77
Choose the flexible query which has generated the following SQL query ?
1 SELECT item_t0.PK, item_t1.p_code
2 FROM products item_t0 LEFT JOIN medias item_t1
3 ON item_t1.PK = item_t0.p_logo
4 WHERE ((item_t0.TypePkString=? AND (item_t1.TypePkString IS NULL OR
( item_t1.TypePkString=? ) )))

1. select {prd.pk}, {md.code} from {Product as prd left join Media as md on


{md.pk} = {prd.logo}}
2. select {prd.pk}, {md.code} from {Product! as prd join Media! as md on
{md.pk} = {prd}}
3. select {prd.pk}, {md.code} from {Product! as prd left join Media! as md
on {md.pk} = {prd.logo}}
4. select {md.code} from {Product as prd left join Media! as md on {md.pk}
= {prd.logo}}
Solution

Mock 2 - Question 78
What service should you use to save an model ?
1. persistenceService
2. jaloService
3. serviceLayerService
4. modelService

Solution

Mock 2 - Question 79
If you are testing a Flexible Search Restriction, the user you are running the
query as ?
1. should be admin
2. should be flexiblesearchquery
3. should be a member of the searchquery group
4. should not be a member of the admin group

Solution

Mock 2 - Question 80
By default when you load an item from the service what is fetched inside the
object ?
1. nothing all attributes are lazy loaded
2. only literal values
3. only references values
4. all

Solution
Solutions
Mock 2 - Solution 1
1,2 are correct.

Question

Mock 2 - Solution 2
2,3 are correct.

Question

Mock 2 - Solution 3
1 is correct.

Question

Mock 2 - Solution 4
3 is correct.

Question

Mock 2 - Solution 5
3 is correct.

Question
Mock 2 - Solution 6
2 is correct.

Question

Mock 2 - Solution 7
4 is correct.

Question

Mock 2 - Solution 8
1,3,4 are correct.

Question

Mock 2 - Solution 9
2,3 are correct.

Question

Mock 2 - Solution 10
1,2,3 are correct.

Question

Mock 2 - Solution 11
1,2,4 are correct.
Question

Mock 2 - Solution 12
1 is correct.

Question

Mock 2 - Solution 13
1,2,3,4 are correct.

Question

Mock 2 - Solution 14
3 is correct.

Question

Mock 2 - Solution 15
4 is correct.
generate=“false” means that Jalo classes won’t be generated.

Question

Mock 2 - Solution 16
3 is correct.

Question
Mock 2 - Solution 17
2 is correct.

Question

Mock 2 - Solution 18
3 is correct.

Question

Mock 2 - Solution 19
4 is correct.

Question

Mock 2 - Solution 20
1 is correct.

Question

Mock 2 - Solution 21
1,2 are correct.

Question

Mock 2 - Solution 22
2 is correct.
Question

Mock 2 - Solution 23
3 is correct.

Question

Mock 2 - Solution 24
2 is correct.

Question

Mock 2 - Solution 25
1 is correct.

Question

Mock 2 - Solution 26
3 is correct.
The installer is not an ant target. extgen would generate a single extension while
here we need to generate a whole new project.

Question

Mock 2 - Solution 27
2 is correct.
Web contexts are contained within a core context (one per tenant), the two
other contexts are not valid.
Question

Mock 2 - Solution 28
3 is correct.

Question

Mock 2 - Solution 29
1,2,3 are correct.

Question

Mock 2 - Solution 30
1 is correct.

Question

Mock 2 - Solution 31
2,3 are correct.

Question

Mock 2 - Solution 32
1,2,4 are correct.

Question
Mock 2 - Solution 33
3 is correct.

Question

Mock 2 - Solution 34
1,2 are correct.

Question

Mock 2 - Solution 35
3 is correct.

Question

Mock 2 - Solution 36
1 is correct.

Question

Mock 2 - Solution 37
2,4 are correct.

Question

Mock 2 - Solution 38
4 is correct.
Question

Mock 2 - Solution 39
2 is correct.

Question

Mock 2 - Solution 40
1,3 is correct.

Question

Mock 2 - Solution 41
3 is correct.

Question

Mock 2 - Solution 42
2 is correct.

Question

Mock 2 - Solution 43
1 is correct.

Question
Mock 2 - Solution 44
3 is correct.

Question

Mock 2 - Solution 45
3 is correct.

Question

Mock 2 - Solution 46
4 is correct.

Question

Mock 2 - Solution 47
2,3 are correct.

Question

Mock 2 - Solution 48
1,2,3,4 are correct.

Question

Mock 2 - Solution 49
1,3,4 are correct.
Question

Mock 2 - Solution 50
3 is correct.

Question

Mock 2 - Solution 51
4 is correct.

Question

Mock 2 - Solution 52
1 is correct.

Question

Mock 2 - Solution 53
1,2,3 are correct.

Question

Mock 2 - Solution 54
1,2 are correct.

Question
Mock 2 - Solution 55
2 is correct.

Question

Mock 2 - Solution 56
1,3 are correct.

Question

Mock 2 - Solution 57
1 is correct.

Question

Mock 2 - Solution 58
1,4 are correct.

Question

Mock 2 - Solution 59
1,2,3 are correct.

Question

Mock 2 - Solution 60
3 is correct.
Question

Mock 2 - Solution 61
2 is correct.

Question

Mock 2 - Solution 62
2 is correct.

Question

Mock 2 - Solution 63
3 is correct.
Have a look at the extension template ygroovy.

Question

Mock 2 - Solution 64
1,2,4 are correct.

Question

Mock 2 - Solution 65
2 is correct.

Question
Mock 2 - Solution 66
1,3 are correct.

Question

Mock 2 - Solution 67
1,3 are correct.

Question

Mock 2 - Solution 68
4 is correct.

Question

Mock 2 - Solution 69
3,4 are correct.

Question

Mock 2 - Solution 70
2 is correct.

Question

Mock 2 - Solution 71
3 is correct.
Question

Mock 2 - Solution 72
3 is correct.

Question

Mock 2 - Solution 73
2 is correct.

Question

Mock 2 - Solution 74
1,2,4 are correct.

Question

Mock 2 - Solution 75
2 is correct.

Question

Mock 2 - Solution 76
2 is correct.

Question
Mock 2 - Solution 77
3 is correct.

Question

Mock 2 - Solution 78
4 is correct.

Question

Mock 2 - Solution 79
4 is correct.

Question

Mock 2 - Solution 80
1 is correct.

Question

You might also like