Uploaded by Catalin

ap-hybris-developer-handbook-62

advertisement
SAP H[y]bris V6.2 Certified
Development Professional
Study Guide (P_HYCD_62)
wcms, backoffice, cockpit, accelerator, data model, order,
search, platform, pcm, price, user
250 questions to prepare the final exam!
@2017 Hybhub
Benoit
Vanalderweireldt
SAP Hybris Commerce 6.2 Developer Study Guide
Benoit Vanalderweireldt
2018-02-01
Contents
1 Introduction
1.1 About the author
1.2 Requirements
1.3 Groovy console
1.4 Assessment test
1.4.1 Questions
1.4.2 Solutions
7
8
8
8
9
10
13
2 WCMS
2.1 CMS Items hierarchy
2.2 CMSItem CMSRelation
2.3 CMSItem types
2.4 CMS Components
2.4.1 Base Stores and websites
2.4.2 Cms component
2.5 Restrictions
2.6 Personalization
2.6.1 Segmentation input rules
2.6.2 Segmentation output actions
2.6.3 Result scope
2.6.4 Evaluation method
2.6.5 Create a CMS segment
2.7 WCMS cockpit
2.8 Point of services
2.8.1 Warehouse
2.8.2 Store
2.9 Warehouse
17
18
18
18
20
20
21
25
27
27
28
28
28
29
29
30
30
31
31
3 Backoffice
3.1 Create a new Backoffice application
3.2 Create and connect a new widget
3.2.1 Widget application context
3.3 Dynamic form
3.3.1 Example how to update the approval status
3.4 Backoffice and tenants
33
34
35
38
39
39
40
4 Cockpit
4.1 Create a new cockpit
4.2 Cockpit modification
43
44
45
2
CONTENTS
3
5 Commerce and Accelerator
5.1 Create a new addon
5.2 OCC Webservices
5.2.1 Install OCC
5.2.2 OAUTH 2
5.2.3 Create / customize webservices
5.3 CMS navigation bar
5.4 Order splitting
5.5 Promotion
5.5.1 Promotion Module
5.5.2 Promotion Engine
5.6 Payment
5.6.1 HOP
5.6.2 SOP
5.6.3 PCI compliance
5.7 Internationalization
5.8 Request handling
5.8.1 Request filters
5.9 Hot folders
5.9.1 Create a new import configuration
5.10 Data Modeling
5.10.1 Create new types
5.11 Flexible Search Query
5.11.1 Cache
5.11.2 Session and restrictions
5.11.3 Restrictions
5.11.4 Examples
5.12 Product Variants & Category Variants
5.12.1 Product Variants
5.12.2 Category Variants
5.13 Classification attributes
47
48
53
56
56
58
64
65
66
66
69
76
77
78
78
78
79
79
82
82
84
84
102
103
103
103
106
108
108
110
111
6 Order management
6.1 Business process
6.2 Fulfillment process
6.3 Shopping cart handling
6.4 Checkout flow
6.5 ASM
6.6 CS Cocpkit
113
114
118
119
120
126
127
7 Search and navigation
7.1 Solr index
7.2 Solr Indexed Property
7.2.1 Solr Indexed Query
7.3 Indexing listeners
7.4 Solr Facet
7.5 Solr Facet Range
7.6 Auto suggestion
7.7 Keywords
131
132
133
136
137
140
140
141
141
4
CONTENTS
7.8 Stopwords
7.9 Synonyms
7.10 Hero products & boost rules
7.10.1 Hero products
7.10.2 Boost rules
142
143
143
143
143
8 Platform basics
8.1 Initialization
8.2 Update
8.3 Update and Initialization lock
8.4 Update and Initialization hooks
8.5 Essential & project data
8.5.1 Import by convention
8.5.2 Import by configuration
8.5.3 Control the order of import
8.6 Sessions handling
8.7 Extensions structures
8.7.1 extensioninfo.xml
8.7.2 localextensions.xml
8.7.3 Create a new extension
8.7.4 Maven
8.8 Configuration
8.8.1 Configuration Service
8.8.2 Environment variables
8.8.3 Runtime optional configuration
8.9 Build
8.9.1 Callbacks
8.10 Tenant
8.11 Cache
8.11.1 Region cache
8.12 Interceptors
8.13 Transactions
8.14 Tasks
149
150
151
151
152
154
154
154
155
155
156
156
157
158
158
159
160
160
161
161
162
162
163
163
165
167
168
9 Platform core
9.1 Events
9.2 Impex
9.2.1 Header
9.2.2 Comment
9.2.3 Macro
9.2.4 Abbreviations
9.2.5 Document ID
9.2.6 Translators
9.2.7 Alternative pattern
9.2.8 Distributed Impex
9.2.9 Access properties from Impex
9.3 Spring context
9.4 Cronjobs
9.4.1 Abortable Cronjob
169
170
173
173
175
176
176
177
177
177
178
178
179
180
182
CONTENTS
9.5
9.6
Cluster
9.5.1 Cache invalidation
9.5.2 Configuration
Testing
9.6.1 Unit tests
9.6.2 Integration tests
9.6.3 Other tests
5
183
184
184
184
185
187
187
10 PCM and price
10.1 Price calculation
10.2 Taxes
10.3 Discounts
10.4 Media object
10.4.1 Media formats and Media container
10.4.2 Media contexts
10.4.3 Secured media
10.5 Synchronization jobs
10.5.1 Dependent Synchronization
10.6 Workflow
189
190
191
192
192
193
194
194
194
195
195
11 User Management
11.1 User rights
11.1.1 Access rights
11.2 Search restrictions
11.2.1 Service layer example
11.2.2 Impex example
11.3 B2B hierarchy
197
198
198
199
200
200
200
12 Study tips
12.1 Study plan
12.2 Play with SAP Hybris
12.3 Identify your weakest point
12.4 Understand the Questions
12.5 Checking the answer
203
204
204
204
205
205
13 Mock exam 1
13.1 Questions
13.2 Solutions
207
208
230
14 Mock exam 2
14.1 Questions
14.2 Solutions
239
240
263
15 Mock exam 3
15.1 Questions
15.2 Solutions
273
274
291
6
CONTENTS
Chapter 1
Introduction
7
8
CHAPTER 1. INTRODUCTION
Dear reader, thank you for choosing SAP Hybris Commerce 6.2 Developer Study Guide to
prepare for your SAP certification. At Hybhub, we would be grateful to have your feedback on this
e-book. Feel free to share your thoughts about this study guide by emailing benoit.v@hybhub.com.
If you disagree or think there are technical errors, please also share it with us.
About the author
Benoit Vanalderweireldt has worked as an SAP Hybris developer for the last five years for
different companies in Asia, US and Europe. Besides being an enthusiastic SAP Hybris developer,
he 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
The following prerequisites are required in order to effectively use this study guide :
1. SAP H[y]bris V6.2
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...)
5. JDK 8 must be 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 on how to load a product with the groovy console:
9
1.4. ASSESSMENT TEST
import
import
import
import
de.hybris.platform.servicelayer.search.FlexibleSearchService
de.hybris.platform.catalog.CatalogVersionService
de.hybris.platform.catalog.model.CatalogVersionModel
de.hybris.platform.core.model.product.ProductModel
FlexibleSearchService fss = spring.getBean("flexibleSearchService")
CatalogVersionService cvs = spring.getBean("catalogVersionService")
CatalogVersionModel cvm = cvs.getCatalogVersion("electronicsProductCatalog","Online")
ProductModel pm = new ProductModel()
pm.setCode("1099413")
pm.setCatalogVersion(cvm)
pm = fss.getModelByExample(pm)
println pm.getName()
Figure 1.1: Example Groovy console
Assessment test
When you prepare for the P_HYCD_62 exam to become a SAP Certified Development Professional - SAP Hybris Commerce 6.2 Developer you have a lot of questions like:
• How do I know when I’m ready for the exam ?
• How hard are the questions ?
• How do I know what chapter I need to focus on ?
• Where can I find a dump of the final exam ? (not here and I strongly suggest you not
to even try)
10
CHAPTER 1. INTRODUCTION
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_62 if you were trying today. So let’s get started; try
to answer all the questions under real conditions.
Questions
Pretest - Question 1
What actions are executed when you initialize SAP Hybris from ant?
• Aborts all running cronjobs
• Delete and recreate the database
• Delete all tables
• Import all project data
Pretest - Question 2
Changing SAP Hybris configuration from the project.properties file of your platform project is
considered bad because ?
• This doesn’t comply with the SAP Hybris licensing model
• It makes future updates harder
• The file is already too big
• This file is ignored after you create a new configuration folder from it
Pretest - Question 3
Is this a valid Flexible Search Query ?
SELECT {p.pk} FROM {Principal} AS p WHERE {p.uid} = ’admin’
• No, Principal is an abstract type
• No, SQL aliases definition needs to be inside the brackets
• No, for another reason
• Yes, this is a valid Flexible Search Query.
11
1.4. ASSESSMENT TEST
Pretest - Question 4
According to the following extensioninfo.xml what statements are true ?
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<extensioninfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="extensioninfo.xsd">
<extension abstractclassprefix="Generated" classprefix="HybhubStorefront"
name="hybhubstorefront">
<requires-extension
<requires-extension
<requires-extension
<requires-extension
<requires-extension
name="assistedservicestorefront"/>
name="smarteditaddon"/>
name="captchaaddon"/>
name="acceleratorstorefrontcommons"/>
name="hybhubfacades"/>
<webmodule jspcompile="false" webroot="/hybhubstorefront"/>
<meta key="extgen-template-extension" value="true"/>
</extension>
</extensioninfo>
• This extension could define new item types from its hybhubstorefront-items.xml like all other
extensions
• This extension can be used as a template to create a new extension
• This extension can define HMC configuration and localization
• This extension requires the presence of a web directory
Pretest - Question 5
Which of the following Interfaces are valid SAP Hybris Interceptors ?
• de.hybris.platform.servicelayer.interceptor.ValidateInterceptor<MODEL>
• de.hybris.platform.servicelayer.interceptor.PrepareInterceptor<MODEL>
• de.hybris.platform.servicelayer.interceptor.CheckInterceptor<MODEL>
• de.hybris.platform.servicelayer.interceptor.InitAllInterceptor<MODEL>
• de.hybris.platform.servicelayer.interceptor.RemoveInterceptor<MODEL>
• de.hybris.platform.servicelayer.interceptor.DeleteInterceptor<MODEL>
12
CHAPTER 1. INTRODUCTION
Pretest - Question 6
What is the recommended way to create a new extension within SAP Hybris V6 ?
• Use the installer script with the extgen recipe
• Extensions are automatically created by the build framework based on your dependencies
• Use the build framework with the extgen ant target to create a new extension from a template
• Use the build framework with the extgen maven goal to create a new extension from a
template
Pretest - Question 7
What bean would I get when I execute spring.getBean("alias") for the following spring configuration?
<alias name="bean1" alias="alias"/>
<bean name="bean1" class="spring.exos.MyBean" />
<alias name="bean2" alias="alias"/>
<bean name="bean2" class="spring.exos.MyBean" />
• bean1
• bean2
• alias
• The configuration is wrong
Pretest - Question 8
Using a standard SAP Hybris configuration, is this a valid item type definition ?
<itemtype code="MyItem" abstract="false" extends="GenericItem">
</itemtype>
• No, this item needs a deployment table
• No, this item needs at least one attribute
• No, only abstract items can extends GenericItem
• No, GenericItem is a not a valid type
• Yes, this is a valid item type definition
1.4. ASSESSMENT TEST
13
Pretest - Question 9
All CMS item types extend ?
• GenericItem
• CMS Item
• CMSItem or CMSRelation
• CatalogAware
Pretest - Question 10
Next Generation (NG) Cockpit dynamic forms can be used to ?
• Automatically generate forms for new item types
• Automatically open the next tab when required data has been entered
• Automatically disable a field when data is being entered
• Automatically create an event when data is validated
Pretest - Question 11
What are the rule engine components (select 2) ?
• Promotion Module
• Rule Builder
• Drool Rules
• Rule Processor
Pretest - Question 12
What steps should you follow in order to integrate Hybris with a new payment provider?
• Use Cybersource extension
• Use OCP extension
• Implement needed commands for the new payment provider
• Configure a new command factory bean
Solutions
Pretest - Solution 1
1,4 are correct.
1. The database is never deleted by SAP Hybris even if the configured database user had ti
right to do so.
2. SAP Hybris will delete only tables he knows from its type definition.
14
CHAPTER 1. INTRODUCTION
Pretest - Solution 2
2 is correct.
Keeping your configuration isolated from SAP Hybris out of the box configuration is recommenced.
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.
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.
Pretest - Solution 5
1,2,5 are correct.
The available interceptors are :
• PrepareInterceptor
• LoadInterceptor
• RemoveInterceptor
• ValidateInterceptor
• InitDefaultsInterceptor
Pretest - Solution 6
3 is correct.
Installer script and the build framework don’t create any extensions. SAP Hybris V6.2 is using
ant to generate new extensions, maven can be used to configure libraries dependencies.
Pretest - Solution 7
2 is correct.
The last configured alias will be used.
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).
1.4. ASSESSMENT TEST
15
Pretest - Solution 9
1,3 are correct.
All item types extend GenericItem type. All CMS item types extend either CMSItem or CMSRelation.
Pretest - Solution 10
2,3 are correct.
Dynamic forms are used to add logic within a wizard or editor area.
Pretest - Solution 11
2,4 are correct.
The rule engine consists of two independent components :
rule builder, UI where you create and maintain rules and rule templates rule processor, process and
execute the rules
Pretest - Solution 12
3,4 are correct.
Cybersource is no longer part of the SAP Hybris commerce distribution, and is suitable only for
Cybersource, not any new payment provider.
You need to implement all payment actions (authorization, capture, void...) for the new payment
provider and configure them within a command factory bean.
16
CHAPTER 1. INTRODUCTION
Chapter 2
WCMS
17
18
CHAPTER 2. WCMS
The SAP Hybris Commerce 6.2 Developer certification expects you to know the Web Content
Management System (WCMS) module extensions. In this chapter, readers will learn the different CMS components and item hierachy, learn how to create new CMS components and restrictions,
explore the store and website data model and learn how to create and manage warehouses and
point of sales. Finally, you will learn how to create segments using the BTG extension.
The WCMS module includes 3 extensions :
• cms2lib (contains cms components, depends on CMS2)
• cmscockpit (cms cockpit customization)
• cms2 (core of the wcms, depends on basecommerce)
A module is a set of extensions
CMS Items hierarchy
Every CMS component inherits from the ’CMSItem’ type. This type declares 3 attributes :
• catalogVersion
• name
• uid
Each CMS component may have multiple versions; default versions are Staged and Online. 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.
Tip 1: CMS and catalogs
CMSItem and CMSRelation are managed inside a content catalog, this catalog is only a
subtype of the hybris catalog and doesn’t add extra functionalities.
CMSItem CMSRelation
CMSItem types
The uniqueness of the types CMSItem and CMSRelation is guaranteed because of a composed key
between catalogVersion and UID. This also means that each item in a specific content catalog can
be considered unique and therefore only exist once.
2.3. CMSITEM TYPES
19
Figure 2.1: Simplified view of the CMS Items hierarchy
<itemtype code="CMSItem" extends="GenericItem">
<attributes>
<attribute qualifier="catalogVersion">
<modifiers unique="true"/>
</attribute>
<attribute qualifier="name">
</attribute>
<attribute qualifier="uid">
<modifiers unique="true"/>
</attribute>
</attributes>
</itemtype>
<itemtype code="CMSRelation" extends="GenericItem">
<attributes>
<attribute qualifier="catalogVersion">
<modifiers unique="true"/>
</attribute>
<attribute qualifier="uid">
<modifiers unique="true"/>
</attribute>
</attributes>
</itemtype>
When do we use CMSItem type and when do we use CMSRelation?
• You can use CMSItem when you create a new CMS item, for instance a new component or
a new type of pages.
20
CHAPTER 2. WCMS
• You can use CMSRelation when you create a new type which is not a CMS component but
still needs to be catalog version aware
CMS Components
A CMS component is 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 component consists 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
Tip 2: Usage
To change how customized item types are rendered within the WCMS cockpit, you
need to create editorArea_myType.xml, contentEditor_myType.xml and wizardConfig_myType.xml.
Base Stores and websites
SAP Hybris divides a store front into two main components:
• a base store
• a website
The following listing will give you a short overview of those two components.
A website (defined through the item type CMSSite)
• the content catalog
• the theme
• the channel (B2B or B2C)
• the homepage
• the URL mapping
• one or more stores
2.4. CMS COMPONENTS
21
A base store (defined through the item type BaseStore)
• the currencies
• product catalogs
• the warehouses
• delivery countries
• tax groups
• point of services
• SOLR configuration
Cms component
CMS components are reusable components that you use to customize your storefronts. They are
easily configurable from the WCMS cockpit. Out of the box the following components exist :
• Paragraph component
• Banner component
• Product list component
• Rotating Images component
You can explore the cmslib extension to find out more about the out of the box cms components.
Now we will create a new CMS component to display a reminder for a order time limit that must
be complied if you want the item to be delivered the following day:
<typegroup name="hybhubCms">
<itemtype code="OrderDeliveryTimeLimitComponent" extends="SimpleCMSComponent"
֒→
autocreate="true" generate="true">
<description>Simple CMS component that displays a reminder of when the limit
time to order for next day delivery</description>
֒→
<attributes>
<attribute qualifier="message" type="localized:java.lang.String">
<persistence type="property" />
</attribute>
</attributes>
</itemtype>
</typegroup>
22
CHAPTER 2. WCMS
First create a new constant for your component in the class ControllerConstants:
package com.hybhub.storefront.controllers;
//All imports
/**
*/
public interface ControllerConstants
{
// Constant names cannot be changed due to their usage in dependant extensions, thus
nosonar
֒→
/**
* Class with action name constants
*/
interface Actions
{
interface Cms // NOSONAR
String _Prefix = "/view/"; // NOSONAR
String _Suffix = "Controller"; // NOSONAR
/**
* Default CMS component controller
*/
String DefaultCMSComponent = _Prefix + "DefaultCMSComponentController"; //
֒→
֒→
NOSONAR
/**
* CMS components that have specific handlers
*/
String OrderDeliveryTimeLimitComponent = _Prefix +
OrderDeliveryTimeLimitComponentModel._TYPECODE + _Suffix;
}
}
}
Now we need to create our controller:
2.4. CMS COMPONENTS
package com.hybhub.storefront.controllers.cms;
import de.hybris.platform.servicelayer.time.TimeService;
import java.text.MessageFormat;
import java.util.Calendar;
import java.util.Date;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import com.hybhub.core.model.OrderDeliveryTimeLimitComponentModel;
import com.hybhub.storefront.controllers.ControllerConstants;
@Controller("OrderDeliveryTimeLimitComponentController")
@RequestMapping(value = ControllerConstants.Actions.Cms.OrderDeliveryTimeLimitComponent)
public class OrderDeliveryTimeLimitComponentController
extends AbstractAcceleratorCMSComponentController
<OrderDeliveryTimeLimitComponentModel>
{
@Resource
private TimeService timeService;
private static final int MAX_HOUR_FOR_NEXT_DAY_DELIVERY = 16;
private static final Date DATE_LIMIT;
static
{
֒→
֒→
֒→
֒→
}
DATE_LIMIT = new Calendar.Builder().set(Calendar.HOUR_OF_DAY,
MAX_HOUR_FOR_NEXT_DAY_DELIVERY).set(Calendar.SECOND, 0)
.build().getTime();
}
@Override
protected void fillModel(final HttpServletRequest request, final Model model,
final OrderDeliveryTimeLimitComponentModel component)
{
final Calendar cal = new
Calendar.Builder().setInstant(timeService.getCurrentTime()).build();
model.addAttribute("nextDayDelivery",
(Boolean.valueOf(cal.get(Calendar.HOUR_OF_DAY) < MAX_HOUR_FOR_NEXT_DAY_DELIVERY)));
model.addAttribute("nextDayDeliveryMessage",
MessageFormat.format(component.getMessage(), DATE_LIMIT));
}
23
24
CHAPTER 2. WCMS
Tip 3: CMS Controller
Creating a controller is not mandatory. If you don’t do it, then the DefaultCMSComponentController will be used, it loads all attributes from the item type into your model.
We need to create a JSP to display our cms component and create a new file hybhubstorefront/
web/webroot/WEB-INF/views/responsive/cms/orderdeliverytimelimitcomponent.jsp:
<%@ page trimDirectiveWhitespaces="true"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<div class="ui-front">
<p>
<c:if test="${nextDayDelivery}">
${nextDayDeliveryMessage}
</c:if>
<c:if test="${not nextDayDelivery}">
<fmt:message key="next.day.delivery.tooLate"/>
</c:if>
</div>
Add this into your localization :
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):
$contentCatalog=electronicsContentCatalog
$contentCatalogName=Electronics Content Catalog
$contentCV=catalogVersion(CatalogVersion.catalog(Catalog.id[default=$contentCatalog]),Catalo ⌋
gVersion.version[default=Online])[default=$contentCatalog:Online]
֒→
INSERT_UPDATE OrderDeliveryTimeLimitComponent;$contentCV[unique=true];uid[unique=true];name; ⌋
message[lang=en];&componentRef;
֒→
;;orderDeliveryTimeLimitComponent;order Delivery Time Limit Component;"Order before {0} to
֒→
receive your order tomorrow.";orderDeliveryTimeLimitComponent;
INSERT_UPDATE ContentSlot;$contentCV[unique=true];uid[unique=true];name;active;cmsComponents ⌋
֒→
(&componentRef)
;;Section1Slot-Homepage;Section1 Slot for Homepage;true;orderDeliveryTimeLimitComponent
25
2.5. RESTRICTIONS
Tip 4: Usage
You should now see your new CMS component under your home page.
Restrictions
Warning!
Do not get flexible search query restrictions mixed up with CMS restrictions ! One is only
adding filters in the FSQL WHERE clause while the other has its own java implementation.
Restrictions can be applied to any CMSItem. They use a Java implementation to filter visible or
hidden items.
26
CHAPTER 2. WCMS
For example the catalog restriction evaluator:
package de.hybris.platform.cms2.servicelayer.services.evaluator.impl;
import
import
import
import
import
de.hybris.platform.catalog.model.CatalogModel;
de.hybris.platform.cms2.model.restrictions.CMSCatalogRestrictionModel;
de.hybris.platform.cms2.servicelayer.data.RestrictionData;
de.hybris.platform.cms2.servicelayer.services.evaluator.CMSRestrictionEvaluator;
org.apache.log4j.Logger;
public class CMSCatalogRestrictionEvaluator implements
֒→
CMSRestrictionEvaluator<CMSCatalogRestrictionModel> {
private static final Logger LOG = Logger.getLogger(CMSCatalogRestrictionEvaluator.class);
public CMSCatalogRestrictionEvaluator() {
}
֒→
֒→
public boolean evaluate(CMSCatalogRestrictionModel catalogaRestrictionModel,
RestrictionData context) {
CatalogModel catalogModel = null;
if(context == null) {
return true;
} else {
if(context.hasProduct()) {
catalogModel = context.getProduct().getCatalogVersion().getCatalog();
} else if(context.hasCategory()) {
catalogModel = context.getCategory().getCatalogVersion().getCatalog();
} else {
if(!context.hasCatalog()) {
LOG.warn("Could not evaluate CMSCatalogRestriction. RestrictionData
contains neither a catalog, a category or a product. Returning false.");
return false;
}
catalogModel = context.getCatalog();
}
return catalogaRestrictionModel.getCatalogs().contains(catalogModel);
}
}
}
Warning!
Each restriction evaluator needs to implement
de.hybris.platform.cms2.servicelayer.services.evaluator.CMSRestrictionEvaluator.
2.6. PERSONALIZATION
27
A restriction also needs an item type definition:
<itemtype code="CMSCatalogRestriction"
֒→
jaloclass="de.hybris.platform.cms2.jalo.restrictions.CatalogRestriction"
extends="AbstractRestriction" autocreate="true" generate="true">
<attributes>
<attribute qualifier="description" type="java.lang.String" redeclare="true">
<persistence type="dynamic"
֒→
attributeHandler="catalogRestrictionDynamicDescription" />
<modifiers write="false" />
</attribute>
</attributes>
</itemtype>
Personalization
The BTG (Behavioral Targeting Group) extension provides the AP module (Advanced Personalization). When the module is activated it allows you to customize which CMSItem to render
for a given customer or to add another CMSItem for a given customer. SAP Hybris customer
segmentation groups your customers into multiple subset and activation actions.
Segmentation input rules
Out of the box, you have access to the following 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
• total sum of all orders
• total order value
• products in last orders
• number of orders in a date range
• last order date
28
CHAPTER 2. WCMS
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 output actions
When a user successfully passes each rule of a segment, an output action is executed. Actions can
be:
• assign a user to a group (used for post rules)
• actions (modify the visibility of cms components)
Result scope
When a segment is fulfilled, the result can be stored in two different scopes:
• session scope (only available option for anonymous users)
• permanent scope, segment rule results are stored for the user (anonymous users or authenticated users)
Evaluation method
There are two ways to evaluate rules:
• Optimized processing, a segment evaluation would stop as soon as one rule is not fulfilled
• Full processing, all rules are evaluated
Warning!
Performances are heavily impacted by full processing, however when running optimized
processing your reports don’t contain all rule evaluation results.
2.7. WCMS COCKPIT
29
Create a CMS segment
Example from the electronics store default segmentation:
##################################################################
# Configuration 1: Regular Customer Segment
##################################################################
INSERT_UPDATE BTGSegment;uid[unique=true];name;sites(uid);active[default=true];scope(code)[d ⌋
efault=ONLINE];$contentCatalogVersion
֒→
;electronicsRegularCustomerSegment;Regular Customer Segment;electronics
INSERT_UPDATE BTGRule;uid[unique=true];code;segment(uid,
֒→
$contentCatalogVersion);ruleType(code);$contentCatalogVersion
;electronicsRegularCustomerRule;Regular Customer Rule;electronicsRegularCustomerSegment;ORDER
INSERT_UPDATE BTGOperator;uid[unique=true];code;$contentCatalogVersion
;electronicsGreaterOperator;numGreaterThanOrEqual
INSERT_UPDATE BTGNumberOfOrdersRelativeDateOperand;uid[unique=true];value;unit(code);$conten ⌋
tCatalogVersion
֒→
;electronicsNumberOfOrdersOperand;6;MONTH
INSERT_UPDATE BTGIntegerLiteralOperand;uid[unique=true];literal;$contentCatalogVersion
;electronicsOrdersIntegerOperand;4
INSERT_UPDATE BTGExpression;uid[unique=true];leftOperand(uid,
$contentCatalogVersion);rightOperand(uid, $contentCatalogVersion);operator(uid,
֒→
$contentCatalogVersion);rule(uid, $contentCatalogVersion);$contentCatalogVersion
֒→
;electronicsRegularCustomerExpression;electronicsNumberOfOrdersOperand;electronicsOrdersInte ⌋
֒→
gerOperand;electronicsGreaterOperator;electronicsRegularCustomerRule
INSERT_UPDATE
֒→
BTGAssignToGroupDefinition;uid[unique=true];code;target;userGroups(uid);segment(uid,
֒→
$contentCatalogVersion);$contentCatalogVersion
;electronicsBtgAssignToRegularGroup;Add to Regular
֒→
Segment;assignToGroup;regulargroup;electronicsRegularCustomerSegment
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 content, 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)
30
CHAPTER 2. WCMS
Point of services
A point of service can be one of the following types:
• store
• warehouse
A point of service is used to attached a physical facility to an SAP Hybris model. Out of the box,
you only have stores and warehouses, but it is possible to extend this by creating new enumeration
values. To do so add this to your custom extension -items.xml file:
<enumtypes>
<enumtype code="PointOfServiceTypeEnum" autocreate="false"
generate="false">
<value code="SERVICEDESK" />
</enumtype>
</enumtypes>
A point of service defines :
• an address
• a longitude
• a latitude
• an employee group attached to this point of service
• hours of services
Tip 5: POS
POS is an abbreviation for point of service.
Warehouse
Warehouses (here we are talking about point of services of warehouse type) are used to attach an
adress to an exisiting warehouse.
Warning!
Don’t get point of service of type warehouse and warehouse mixed up!
31
2.9. WAREHOUSE
To create a new point of service of type warehouse:
INSERT_UPDATE
PointOfService;name[unique=true];displayName;warehouses(code);address(&addrID);latitude ⌋
֒→
֒→
;longitude;geocodeTimestamp[dateformat=dd.MM.yyyy];type(code)[default=WAREHOUSE]
;warehouse_s;Warehouse South;warehouse_s;warehouse_s;33,5933317;130,3515247;11.12.2025
Store
Stores are an essential component for the click and collect functionality, customers want to know
if a given product is available at the physical store and if it is they might also want to pick the
product directly there. Stores are also a way for you to publish your stores opening hours and few
extra informations.
To create a new point of service of type store:
INSERT_UPDATE PointOfService;name[unique=true];address(&addrID);latitude;longitude;geocodeTi ⌋
mestamp[dateformat=dd-MM-yyyy];openingSchedule(code);basestore(uid)[default=$storeUid]; ⌋
֒→
features(code);type(code)[default=STORE]
֒→
;WSI-Nakano;WSI-Nakano;35,6894875;139,6917064;29-04-2011;$standardHours
Warehouse
Figure 2.2: Warehouse item type
32
CHAPTER 2. WCMS
Warehouses are attached to one or more stores, and to stock levels and consignments. They are
used by the stock level service to return a stock level status for a given product and a given base
store.
To define a new warehouse:
$vendor=electro
# Create some Warehouses for the Vendor
INSERT_UPDATE
֒→
Warehouse;code[unique=true];vendor(code)[default=$vendor];default[default=’false’]
;Nakano
To define a new stock level:
INSERT_UPDATE StockLevel;available;warehouse(code)[unique=true];inStockStatus(code);maxPreOr ⌋
֒→
der;maxStockLevelHistoryCount;overSelling;preOrder;productCode[unique=true];reserved
;6;warehouse_1;notSpecified;0;-1;0;0;product1;0
Example on how to call the stock level service (if the out-of-the-box electronic store is available,
this should print "inStock"):
def
def
def
def
commerceStockService = spring.getBean("commerceStockService")
baseStoreDao = spring.getBean("baseStoreDao")
catalogService = spring.getBean("catalogService")
productService = spring.getBean("productService")
def elecStore = baseStoreDao.findBaseStoresByUid("electronics").get(0)
def elecCatalog = catalogService.getCatalogVersion("electronicsProductCatalog", "Online")
def product = productService.getProductForCode(elecCatalog, "5897548")
def stockLevel = commerceStockService
.getStockLevelStatusForProductAndBaseStore(product, elecStore)
println stockLevel
Chapter 3
Backoffice
33
34
CHAPTER 3. BACKOFFICE
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 framework.
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 current backoffice itself.
Create a new Backoffice application
To create a new backoffice application run the ant target ant extgen and select the template
ybackoffice. Then, 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
<meta key="backoffice-module" value="true" />
Any backoffice extension has a backoffice folder with the following structure:
• src folder for your backoffice components code (for example, the controllers),
• resources/cng for all static files,
• resources/widgets. Each widget has its own directory with a definition.xml file, a zul a
template, a css style sheet folders for images an localization. The widgets folder may also
contain sub directories for actions and editors.
Tip 6: Usage
For more details, generate a new custom extension using the extgen ant target and use the
ybackoffice template (don’t forget to generate an example widget).
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 reorganizes 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).
Tip 7: Usage
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.
3.2. CREATE AND CONNECT A NEW WIDGET
35
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 and connect a new widget
Tip 8: To speed up widgets development deactivate all cache
backoffice.cockpitng.additionalResourceLoader.enabled=true
backoffice.cockpitng.uifactory.cache.enabled=false
backoffice.cockpitng.widgetclassloader.resourcecache.enabled=false
backoffice.cockpitng.resourceloader.resourcecache.enabled=false
36
CHAPTER 3. BACKOFFICE
We will Create a widget to filter reviews by status, to do so create a new folder customerreviewselectorbackofficewidget inside your custom backoffice extension (the one created with the ybackoffice
template). This folder will contain our widget configuration, create a file definition.xml with the
following content :
<widget-definition xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://www.hybris.com/schema/cockpitng/widget-definit ⌋
ion.xsd"
֒→
id="com.hybhub.backoffice.widgets.customerreviewselectorbackofficewidget">
<name>Customer Review Selector</name>
<description>Customer Review Selector - Select pending reviews, denied reviews or
֒→
approved reviews </description>
<defaultTitle>Customer Review Selector</defaultTitle>
<author>Hybhub</author>
<version>1.0</version>
<view src="customerreviewselectorwidget.zul" />
<keywords>
<keyword>customerreviewselector</keyword>
</keywords>
<controller class="com.hybhub.backoffice.widgets.CustomerreviewbackofficeController"
֒→
/>
<settings>
<setting key="type" type="ENUM(Pending,Approved,Rejected)"/>
<setting key="name" type="String"/>
</settings>
<sockets>
<output type="com.hybris.cockpitng.search.data.pageable.Pageable"
֒→
id="reviews"/>
</sockets>
</widget-definition>
3.2. CREATE AND CONNECT A NEW WIDGET
And a view hybhubbackofficewidget.zul in the same folder with the following content :
<?xml version="1.0" encoding="UTF-8"?>
<widget xmlns="http://www.zkoss.org/2005/zul"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:h="http://www.w3.org/1999/xhtml"
xmlns:w="http://www.zkoss.org/2005/zk/client"
xmlns:zk="http://www.zkoss.org/2005/zk"
xsi:schemaLocation="http://www.zkoss.org/2005/zul
֒→
http://www.hybris.com/schema/cockpitng/zul/zul.xsd"
height="100%">
<div height="100%" style="background: #ccc;">
<div>
<button id="reviews" label="Pending Reviews"/>
</div>
<widgetchildren slotID="additionalArea" id="additionalArea" type="tab"
֒→
width="100%" height="100%"/>
</div>
</widget>
37
38
CHAPTER 3. BACKOFFICE
Create a controller inside your backoffice extension backoffice/src folder :
package com.hybhub.backoffice.widgets;
import de.hybris.platform.customerreview.enums.CustomerReviewApprovalType;
import de.hybris.platform.customerreview.model.CustomerReviewModel;
import
import
import
import
org.zkoss.zk.ui.Component;
org.zkoss.zk.ui.event.Events;
org.zkoss.zk.ui.select.annotation.WireVariable;
org.zkoss.zul.Button;
import
import
import
import
com.hybhub.services.CustomerReviewSearchService;
com.hybris.cockpitng.annotations.ViewEvent;
com.hybris.cockpitng.search.data.pageable.PageableList;
com.hybris.cockpitng.util.DefaultWidgetController;
public class CustomerreviewbackofficeController extends DefaultWidgetController
{
private Button reviews;
@WireVariable
private CustomerReviewSearchService customerReviewSearchService;
@Override
public void initialize(final Component comp)
{
super.initialize(comp);
reviews.setLabel(this.getWidgetSettings().getString("name"));
}
@ViewEvent(componentID = "reviews", eventName = Events.ON_CLICK)
public void sendReviews()
{
final CustomerReviewApprovalType approvalType = CustomerReviewApprovalType
.valueOf(this.getWidgetSettings().getString("type"));
֒→
sendOutput("reviews", new PageableList<CustomerReviewModel>(customerReviewSe ⌋
archService.getAllCustomerReviews(approvalType),
10, CustomerReviewModel._TYPECODE));
}
}
Widget application context
The widgets have their own spring application context (child of the web application context) with
auto-reload capabilities during runtime.
3.3. DYNAMIC FORM
39
Tip 9: Usage
Remember that in order to override a bean you need to load your extensions in the correct
order using extension dependencies within the extensioninfo.xml.
In order to load a bean from a widget controller you can use:
@WireVariable
private UserService userService;
If you need to load a spring bean outside of a widget controller use:
com.hybris.cockpitng.util.BackofficeSpringUtil.getBean(String name, Class<? extends C> clz)
Dynamic form
Dynamic form is a new feature for backoffice applications. They bring more control and interactivity over the data entered from the backoffice. They can be configured directly from the backoffice itself or from the backoffice configuration files (myextension/resources/myextension-backofficeconfig.xml). Dynamic forms can perform action on attributes, sections and tabs. You can write
action in Groovy, Bean Shell, Javascript and spel. To customize dynamic forms directly from the
Backoffice, access the application orchestrator (press f4), then select show cockpit-config.xml from
the top right corner. Filter components with editorAreaDynamicForms.
Tip 10: Dynamic forms
Dynamic forms can execute actions on attributes, sections and tabs.
Example how to update the approval status
Here we would like a product to have a disaproved status whenever somebody update any model
attribute (this shouldn’t be applied for the user responsible for approving products). To do so, we
customize one of the -backoffice-config.xml file or we update the cockpit-config.xml directly from
the ordchestrator.
40
CHAPTER 3. BACKOFFICE
<context type="Product" component="editorAreaDynamicForms" merge-by="module">
<df:dynamicForms xmlns:df="http://www.hybris.com/cockpitng/component/dynamicForms">
<df:attribute id="uniqueIdForTheAction" triggeredOn="}"
֒→
qualifier="approvalStatus"
computedValue="T(de.hybris.platform.catalog.enums.ArticleApprovalStatus).UNAPPROVED" />
</df:dynamicForms>
</context>
֒→
• triggeredOn="*", get triggered for any change on the model
• qualifier="approvalStatus", the targeted attribute
• computedValue=...., the value of the targeted attribute
Warning!
Now every time you update a product, the approval status is automatically set to unapproved.
ArticleApprovalStatus is used for products approval status on Hybris 6.2, this is confusing
but the enum name has no impacts.
Backoffice and tenants
Out of the box tenant selection is not available for backoffice applications. Here is how you can
add a junit context path for the backoffice:
Create a file named : local_tenant_junit.properties under your configuration folder, it should
contain :
backoffice.webroot=/backoffice_junit
Create a file for customization inside your config folder
customize/ext-backoffice/backoffice/web/webroot/WEB-INF/backoffice-spring-filter.xml. Copy the
content of the original file and update the backofficeFilterChain bean. We want to use the dynamicTenantActivationFilter instead of the tenantActivationFilter):
3.4. BACKOFFICE AND TENANTS
41
<bean id="backofficeFilterChain"
֒→
class="de.hybris.platform.servicelayer.web.PlatformFilterChain">
<constructor-arg>
<list>
<ref bean="log4jFilter"/>
<ref bean="dynamicTenantActivationFilter"/>
<ref bean="backofficeRedirectFilter"/>
<ref bean="sessionFilter"/>
<ref bean="backofficeDataSourceSwitchingFilter"/>
<ref bean="backofficeCatalogVersionActivationFilter"/>
<ref bean="backofficeContextClassloaderFilter"/>
<ref bean="backofficeSecureMediaFilter" />
</list>
</constructor-arg>
1. Execute ant clean all customize.
2. Check that in bin/platform/tomcat/conf/server.xml you now have a new context backoffice_junit.
3. Start your server, you can now access the backoffice application for master and junit tenant.
42
CHAPTER 3. BACKOFFICE
Chapter 4
Cockpit
43
44
CHAPTER 4. COCKPIT
Sap Hybris has a cockpit framework used to build backend applications. The framework is based
on ZK a RIA framework (rich internet application). ZK has a large set of UI components that can
be used across all backend applications to speed up the development. The cockpit framework is
provided by the cockpit extension.
The out-of-the-box available cockpits are:
• Customer Service Cockpit (order and customer management);
• Hybris Management Console (administration cockpit);
• Import Cockpit (import data from CSV files);
• Hybris Print Cockpit (export your catalog for printing);
• Hybris Product Cockpit (manafe your products);
• Report Cockpit (create and view dashboards);
• WCMS Cockpit (web content management cockpit).
Warning!
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.
Create a new cockpit
To create a new cockpit, use the available template ycockpit with the extgen ant target. For
example:
{12:02}~/bin/platform:master -> ant extgen
...
ycockpit
...
hybhubcockpit
...
com.hybhub.cockpit
Then, add the new extension into your localextensions.xml file (here hybhubcockpit). Compile
and start your server. Your new cockpit is available at http://localhost:9001/hybhubcockpit. By
default, you will have one perspective for Product models.
4.2. COCKPIT MODIFICATION
45
You can easily add new perspectives by adding a bean reference into the availablePerspectives
property of the UICockpitSession bean (open the file resources/extensionName/extensionNameweb-spring.xml):
<property name="availablePerspectives">
<list>
<ref bean="HybhubcockpitPerspective"/>
<ref bean="HybhubcockpitMediaPerspective" /> <!-- Custom perspective for
֒→
Medias -->
</list>
</property>
<bean id="HybhubcockpitMediaPerspective" scope="session" parent="BasePerspective">
<property name="uid" value="hybhubcockpit.perspective.hybhubmediacockpit" />
<property name="label" value="perspective.hybhubmediacockpit" />
<property name="customCsaURI" value="/hybhubcockpit/hybhubcockpitCSA.zul" />
<property name="navigationArea">
<ref bean="HybhubcockpitNavigationArea" />
</property>
<property name="browserArea">
<bean class="com.hybhub.cockpit.session.impl.HybhubcockpitBrowserArea">
<property name="rootSearchTypeCode" value="Media"/>
<property name="viewURI" value="/cockpit/baseSearchBrowserArea.zul"/>
</bean>
</property>
<property name="editorArea">
<bean id="HybhubcockpitMediaEditorAreaModel" parent="BaseEditorAreaModel">
<property name="editorAreaController">
<ref bean="HybhubcockpitEditorAreaController"/>
</property>
</bean>
</property>
<property name="popupEditorArea">
<bean id="HybhubcockpitMediaPopupEditor" parent="BasePopupEditor">
<property name="editorAreaController">
<ref bean="HybhubcockpitPopupEditorAreaController"/>
</property>
</bean>
</property>
<property name="cockpitTypeService" ref="cockpitTypeService"/>
</bean>
Cockpit modification
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.
46
CHAPTER 4. COCKPIT
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/<extensionName>-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 5
Commerce and Accelerator
47
48
CHAPTER 5. COMMERCE AND ACCELERATOR
Create a new addon
Addons are used to extend the functionalities 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 can do the following:
• add frontend files (JSP, HTML, CSS and Javascript);
• Generate or customize Facade transferred 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.
5.1. CREATE A NEW ADDON
49
First you need to generate a new extension based on the yaddon template. I called my extension
hybhubaddon and chose com.hybhub.hybhubaddon as a package name:
Buildfile:
֒→
/Users/j.doe/Workspace/workspace-perso/hybris/hybris-6.2.0/hybris/bin/platform/build.xml
[echo] /Workspace/hybris/hybris-6.2.0/hybris/bin/platform/tomcat/bin
.....
[echo] ----[echo] hybris Platform Environment
[echo] ----[echo] OS family:
unix
[echo] Java platform:
Java(TM) SE Runtime Environment, 1.8.0_60-b27
[echo] Java compiler:
org.eclipse.jdt.core.JDTCompilerAdapter
1.8
[echo] Build target:
[echo] Compilation mode:
strict
[echo] hybris Platform directory: /Workspace/hybris/hybris-6.0.0/hybris/bin/platform
6.0.0.0-SNAPSHOT
[echo] hybris Platform version:
[echo] Ant version:
Apache Ant(TM) version 1.9.1 compiled on May 15 2013
[echo] Ant memory settings:
-Xmx512m -Dfile.encoding=UTF-8
[echo] ----.....
extgen:
[input]
[input] Please choose a template for generation.
[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)
֒→
yaddon
[input]
[input] Please choose the name of your extension. It has to start with a letter followed
by letters and/or numbers.
֒→
[input] Press [Enter] to use the default value [training]
hybhubaddon
[input]
[input] Please choose the package name of your extension. It has to fulfill java package
֒→
name convention.
[input] Press [Enter] to use the default value [org.training]
com.hybhub.hybhubaddon
.......
[echo]
Next steps:
[echo]
[echo] 1) Add your extension to your
֒→
/Workspace/hybris/hybris-6.0.0/hybris/config/localextensions.xml
[echo]
<extension
[echo]
֒→
dir="/Workspace/hybris/hybris-6.0.0/hybris/bin/custom/hybhubaddon"/>
[echo]
[echo] 2) Please remove all template extensions (again) before you proceed.
[echo]
[echo] 3) Make sure the applicationserver is stopped before you build the extension the
first time.
֒→
[echo]
[echo] 4) Perform ’ant’ in your hybris/platform directory.
[echo]
[echo] 5) Restart the applicationserver
[echo]
[echo]
BUILD SUCCESSFUL
Total time: 29 seconds
50
CHAPTER 5. COMMERCE AND ACCELERATOR
After adding your addon to your eclipse environment and to your localextensions.xml file, you will
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 frontend extension.
Figure 5.1: Addon accelerator folder structure
Next step is to install your addon into the designated store front extension. For this, we use ant:
ant addoninstall -Daddonnames="AddOnName1,AddOnName2"
֒→
-DaddonStorefront.yacceleratorstorefront="B2CStorefront1,B2CStorefront2"
֒→
-DaddonStorefront.yb2bacceleratorstorefront="B2BStorefront1,B2BStorefront2"
5.1. CREATE A NEW ADDON
51
In my case my addon’s name is hybhubaddon and the storefront extension I’m using is yacceleratorstorefront so I need to execute :
ant addoninstall -Daddonnames="hybhubaddon"
֒→
-DaddonStorefront.yacceleratorstorefront="yacceleratorstorefront"
.....
addoninstall:
[echo] Storefront templates found in command line : yacceleratorstorefront,
[delete] Deleting: /Workspace/hybris/hybris-6.0.0/hybris/bin/platform/null2070331373
[echo] AddOn name list: hybhubaddon
[echo] ------------------Instaling addon : hybhubaddon--------------[echo] Generate project.properties file from template
֒→
/Workspace/hybris/hybris-6.0.0/hybris/bin/custom/hybhubaddon/project.properties.template
[copy] Copying 1 file to /Workspace/hybris/hybris-6.0.0/hybris/bin/custom/hybhubaddon
[echo] Add additionalWebSpringConfigs line for storefrontTemplate
֒→
’yacceleratorstorefront’ and storefronts ’yacceleratorstorefront’
[propertyfile] Updating property file:
֒→
/Workspace/hybris/hybris-6.0.0/hybris/bin/custom/hybhubaddon/project.properties
[echo] Adding addon ’hybhubaddon’ to extensioninfo.xml for ’yacceleratorstorefront’
[echo] Adding addon ’hybhubaddon’ to addons.less for ’yacceleratorstorefront’
BUILD SUCCESSFUL
Total time: 2 seconds
The addoninstall target does a couple of things:
• Generate a new project.properties file from the project.properties.template inside your addon.
• Configure the hybhubaddon web spring configuration hybhubaddonweb-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 can use:
ant addonuninstall -Daddonnames="hybhubaddon"
֒→
-DaddonStorefront.yacceleratorstorefront="yacceleratorstorefront"
.....
addonuninstall:
[echo] Storefront templates found in command line : yacceleratorstorefront,
[delete] Deleting: /Workspace/hybris/hybris-6.0.0/hybris/bin/platform/null583120343
[echo] AddOn name list: hybhubaddon
[echo] ------------------Uninstaling addon : hybhubaddon--------------[echo] Removing addon ’hybhubaddon’ from extensioninfo.xml for ’yacceleratorstorefront’
[echo] Removing addon ’hybhubaddon’ from addons.less for ’yacceleratorstorefront’
BUILD SUCCESSFUL
Total time: 2 seconds
52
CHAPTER 5. COMMERCE AND ACCELERATOR
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:
<%@ page trimDirectiveWhitespaces="true"%>
<%@ taglib prefix="template" tagdir="/WEB-INF/tags/responsive/template"%>
<template:page pageTitle="${pageTitle}">
<h1>From Hybhub Addon</h1>
</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):
package com.hybhub.hybhubaddon.controllers.pages;
import de.hybris.platform.addonsupport.controllers.page.AbstractAddOnPageController;
import de.hybris.platform.cms2.exceptions.CMSItemNotFoundException;
import de.hybris.platform.cms2.model.pages.ContentPageModel;
import
import
import
import
org.springframework.stereotype.Controller;
org.springframework.ui.Model;
org.springframework.web.bind.annotation.RequestMapping;
org.springframework.web.bind.annotation.RequestMethod;
@Controller
@RequestMapping(value = "/hybhub")
public class HybHubAddonPageController extends AbstractAddOnPageController
{
@RequestMapping(method = RequestMethod.GET)
public String hybhub(final Model model) throws CMSItemNotFoundException
{
final ContentPageModel page = getContentPageForLabelOrId(null);
storeCmsPageInModel(model, page);
setUpMetaDataForContentPage(model, page);
return "addon:/hybhubaddon/pages/layout/hybhubAddonLayout";
}
}
53
5.2. OCC WEBSERVICES
Update the file hybhubaddon/resources/hybhubaddon/web/spring/hybhubaddon-web-spring.xml to
add a context component-scan element:
<context:annotation-config/>
<context:component-scan base-package="com.hybhub.hybhubaddon.controllers"/>
Build your platform and start your server, now when you access https://localhost:9002/yacceleratorstorefront/
electronics/en/hybhub?site=electronics you should see :
Figure 5.2: Hybhub Addon Page
Tip 11: Addons
What have we done? We have customized the store front extension without changing its
sources. We could easily inject our changes on any other project or future Hybris releases.
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.
54
CHAPTER 5. COMMERCE AND ACCELERATOR
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
Tip 12: Extension templates
Remember that all extensions starting with a y are templates. For example to add new
webservices or to customize existing one, you need to generate a new commerce web service
extensions from the ycommercewebservices template.
Currently 2 versions of the web services coexists:
1. 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).
2. 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)
Tip 13: auth access
Remember that OCC doesn’t use normal users. It has its own data type to manage credentials. Have a look at OAuthClientDetails.
5.2. OCC WEBSERVICES
<itemtype code="OAuthClientDetails" generate="true" autocreate="true" >
<deployment table="OAuthClientDetails" typecode="6500" />
֒→
<attributes>
<attribute qualifier="clientId" type="java.lang.String">
<description>Client Id</description>
<modifiers unique="true" optional="false" initial="true"
write="false" />
<persistence type="property" />
</attribute>
<attribute qualifier="resourceIds" type="StringSet">
<description>Set of Resource Id’s</description>
<persistence type="property" />
</attribute>
<attribute qualifier="clientSecret" type="java.lang.String">
<description>Client Secret</description>
<persistence type="property" />
</attribute>
<attribute qualifier="scope" type="StringSet">
<description>Set of client scopes</description>
<persistence type="property" />
</attribute>
<attribute qualifier="authorizedGrantTypes" type="StringSet">
<description>Set of grant types for client</description>
<persistence type="property" />
</attribute>
<attribute qualifier="registeredRedirectUri" type="StringSet">
<description>Set of redirect Uri for client</description>
<persistence type="property" />
</attribute>
<attribute qualifier="authorities" type="StringSet">
<description>Set of authorities granted to client</description>
<persistence type="property" />
</attribute>
<attribute qualifier="accessTokenValiditySeconds" type="java.lang.Integer">
<description>Set of authorities granted to client</description>
<persistence type="property" />
</attribute>
<attribute qualifier="refreshTokenValiditySeconds" type="java.lang.Integer">
<description>Set of authorities granted to client</description>
<persistence type="property" />
</attribute>
<attribute qualifier="autoApprove" type="StringSet">
<description>Set of auto approve scopes of client</description>
<persistence type="property" />
</attribute>
</attributes>
<indexes>
<index name="clientIdIdx" unique="true">
<key attribute="clientId" />
</index>
</indexes>
</itemtype>
55
56
CHAPTER 5. COMMERCE AND ACCELERATOR
Install OCC
To activate and use the Omni Channel Connect module, you need to have these extensions activated:
• ycommercewebservices;
• ycommercewebserviceshmc;
• ycommercewebservicestest;
• commercewebservicescommons;
• webservicescommonsbackoffice;
• cmswebservices.
Warning!
If you have created your own web services extensions from the y templates (using modulegen
with commercewebservices), 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 will be able to
manage the OAuthClientDetails and see the current OAuthAccessToken from the backoffice.
Figure 5.3: Backoffice OAuth
OAUTH 2
Hybris web services authorization mechanism is based on (https://oauth.net/2/) which is the
industry standard protocol. Each call to the OCC web services have to go through a complex
authorization 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 applies its own
set of verification.
57
5.2. OCC WEBSERVICES
OCC user roles
Authentification type
Anonymous
Client
Customers
Guest
Role
A non-authenticated principal is assigned a
built-in ANONYMOUS role by default.
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
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.
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 can import the one provided with the
cmswebservices extension inside the impex file sampledata-oauthclients.impex.
INSERT_UPDATE OAuthClientDetails;clientId[unique=true];resourceIds;scope;authorizedGrantType ⌋
s;authorities;clientSecret;registeredRedirectUri
֒→
;client-side;hybris;basic;implicit,client_credentials;ROLE_CLIENT;secret;http://localhost:90 ⌋
01/authorizationserver/oauth2_implicit_callback;
֒→
;mobile_android;hybris;basic;authorization_code,refresh_token,password,client_credentials;RO ⌋
LE_CLIENT;secret;http://localhost:9001/authorizationserver/oauth2_callback;
֒→
;trusted_client;hybris;extended;authorization_code,refresh_token,password,client_credentials ⌋
֒→
;ROLE_TRUSTED_CLIENT;secret;;
58
CHAPTER 5. COMMERCE AND ACCELERATOR
Curl
curl -k -X POST https://localhost:9002/authorizationserver/oauth/token\?client_id\=trusted_c ⌋
֒→
lient&client_secret\=secret&grant_type=client_credentials
{
"access_token" : "16582579-a158-4c31-ad3a-438c9e587dae",
"token_type" : "bearer",
"scope" : "extended",
"expires_in" : 41780
}%
Tip 14: Usage
-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
Figure 5.4: Postman
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 storefront you use the yacceleratorstorefront template to generate
a new extension from where you start your development.
5.2. OCC WEBSERVICES
Tip 15: Usage
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.
59
60
CHAPTER 5. COMMERCE AND ACCELERATOR
The first step is to generate a new extension from the ycommercewebservices extension:
: platform ant extgen
Buildfile: /Workspace/hybris/hybris-6.0.0/hybris/bin/platform/build.xml
[echo] /Workspace/hybris/hybris-6.0.0/hybris/bin/platform/tomcat/bin
[echo] /Workspace/hybris/hybris-6.0.0/hybris/bin/platform/ext/core/web/webroot/WEB-INF/ ⌋
external-dependencies.xml was not
֒→
found!
֒→
[ysetplatformproperties] Starting platform in extgen mode...
...
...
[echo] commercesearchbackoffice->(backoffice,cms2,commercesearch,commercefacades)
֒→
6.0.0.0-SNAPSHOT [cib]
֒→
path:/Workspace/hybris/hybris-6.0.0/hybris/bin/ext-backoffice/commercesearchbackoffice
[echo] mcc->(impex,processing,cockpit) 6.0.0.0-SNAPSHOT [ciw]
֒→
path:/Workspace/hybris/hybris-6.0.0/hybris/bin/ext-cockpit/mcc
[echo] ----[echo]
extgen:
[input]
[input] Please choose a template for generation.
[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)
ycommercewebservices
[input]
[input] Please choose the name of your extension. It has to start with a letter followed
֒→
by letters and/or numbers.
[input] Press [Enter] to use the default value [training]
mywebservices
[input]
[input] Please choose the package name of your extension. It has to fulfill java package
֒→
name convention.
[input] Press [Enter] to use the default value [org.training]
com.hybhub.webservices
[echo] Using extension template source:
֒→
/Workspace/hybris/hybris-6.0.0/hybris/bin/ext-template/ycommercewebservices
[mkdir] Created dir: /Workspace/hybris/hybris-6.0.0/hybris/temp/hybris/extgen
[echo]
Next steps:
[echo] 1) Add your extension to your
֒→
/Users/workspace-perso/hybris/hybris-6.0.0/hybris/config/localextensions.xml
[echo]
<extension
֒→
dir="/Workspace/hybris/hybris-6.0.0/hybris/bin/custom/mywebservices"/>
[echo] 2) Please remove all template extensions (again) before you proceed.
[echo] 3) Make sure the applicationserver is stopped before you build the extension the
֒→
first time.
[echo] 4) Perform ’ant’ in your hybris/platform directory.
[echo] 5) Restart the applicationserver
BUILD SUCCESSFUL
Total time: 27 seconds
: platform
5.2. OCC WEBSERVICES
61
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.
<hybrisconfig xmlns:xsi=’http://www.w3.org/2001/XMLSchema-instance’
֒→
xsi:noNamespaceSchemaLocation=’../bin/platform/resources/schemas/extensions.xsd’>
<extensions>
<path dir=’\${HYBRIS_BIN_DIR}’ autoload=’false’ />
...
<extension name="mywebservices"/>
...
</extensions>
</hybrisconfig>
Tip 16: Check current build
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:
62
CHAPTER 5. COMMERCE AND ACCELERATOR
package com.hybhub.webservices.v2.controller;
import
import
import
import
import
import
import
import
import
de.hybris.platform.servicelayer.cronjob.CronJobService;
java.util.stream.Collectors;
javax.annotation.Resource;
org.springframework.security.access.annotation.Secured;
org.springframework.stereotype.Controller;
org.springframework.web.bind.annotation.RequestMapping;
org.springframework.web.bind.annotation.RequestMethod;
org.springframework.web.bind.annotation.ResponseBody;
com.hybhub.webservices.dto.cronjob.CronJobListWsDTO;
@Controller
@RequestMapping(value = "/{baseSiteId}/cronjobs")
public class CronJobsController extends BaseController
{
@Resource
CronJobService cronJobService;
֒→
@Secured("ROLE_TRUSTED_CLIENT")
@RequestMapping(value = "/running", method = RequestMethod.GET)
@ResponseBody
public CronJobListWsDTO getRunningCronJobCode()
{
final CronJobListWsDTO cronJobList = new CronJobListWsDTO();
cronJobList.setCronJobsCode(
cronJobService.getRunningOrRestartedCronJobs().
parallelStream().map(c ->
c.getCode()).collect(Collectors.toList()));
return cronJobList;
}
}
We need to create the java bean CronJobListWsDTO using mywebservices-beans.xml file:
<bean class="com.hybhub.webservices.dto.cronjob.CronJobListWsDTO">
<property name="cronJobsCode" type="java.util.List<java.lang.String>"/>
</bean>
Run ant clean all then start your server. Check that you have at least one running cronjob otherwise
your list will be empty, then you can call our newly created webservice:
Warning!
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. Marshalers operate mainly on properties and,
63
5.2. OCC WEBSERVICES
Figure 5.5: Postman Cronjobs
because of this, marshaling performed with commonly used 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 configuration for our cronjob
controller, open the file mywebservices/web/webroot/WEB-INF/cache/ehcache.xml and add :
<cache name="cronjobCache"
maxElementsInMemory="1"
eternal="false"
overflowToDisk="true"
timeToLiveSeconds="30"
diskPersistent="false"
maxElementsOnDisk="100"
memoryStoreEvictionPolicy="LRU"/>
Then update our controller to be Cachable. 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:
@Controller
@CacheControl(directive = CacheControlDirective.PUBLIC, maxAge = 30)
@RequestMapping(value = "/{baseSiteId}/cronjobs")
public class CronJobsController extends BaseController
...
@Secured("ROLE_TRUSTED_CLIENT")
@RequestMapping(value = "/running", method = RequestMethod.GET)
@Cacheable(value = "cronjobCache", key = "T(de.hybris.platform.commercewebservicescommons.ca ⌋
che.CommerceCacheKeyGenerator).generateKey(false,false,’getRunningCronJobCode’)")
֒→
@ResponseBody
public CronJobListWsDTO getRunningCronJobCode()
Now it should take 30 seconds before any changes to cronjobs status appear when you call our
cronjob.
64
CHAPTER 5. COMMERCE AND ACCELERATOR
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.
5.4. ORDER SPLITTING
65
$contentCatalog=electronicsContentCatalog
$contentCatalogName=Electronics Content Catalog
$contentCV=catalogVersion(CatalogVersion.catalog(Catalog.id[default=$contentCatalog]),Catalo ⌋
gVersion.version[default=Online])[default=$contentCatalog:Online]
֒→
$productCatalog=electronicsProductCatalog
$productCatalogName=Electronics Product Catalog
$productCV=catalogVersion(catalog(id[default=$productCatalog]),version[default=’Staged’])[un ⌋
֒→
ique=true,default=$productCatalog:Staged]
$category=category(code, $productCV)
#First we create a Root node
INSERT_UPDATE CMSNavigationNode;uid[unique=true];$contentCV[unique=true];name;children(uid,$ ⌋
֒→
contentCV)[mode=append]
;rootNode;;rootNode;;
#We create the needed links
INSERT_UPDATE CMSLinkComponent;$contentCV[unique=true];uid[unique=true];name;url;&linkRef;\& ⌋
֒→
componentRef;target(code)[default=’sameWindow’];$category;
;;HomepageNavLink;Home Page Nav Link;/;HomepageNavLink;HomepageNavLink;;;
;;CamerasCategoryLink;Cameras Category Link;;CamerasCategoryLink;CamerasCategoryLink;;571;
;;HackerNewsNavLink;Hacker News Page Nav
֒→
Link;https://news.ycombinator.com/news;HackerNewsNavLink;HackerNewsNavLink;;;
;;GitHubNavLink;Git Hub Page Nav Link;https://github.com;GitHubNavLink;GitHubNavLink;;;
#We Create the nodes
INSERT_UPDATE CMSNavigationNode;uid[unique=true];$contentCV[unique=true];name;parent(uid,
$contentCV);links(&linkRef);&nodeRef
֒→
;ElectronicsNavNode;;Electronics Site;rootNode;HomepageNavLink;ElectronicsNavNode
;CamerasNavNode;;Cameras Category;rootNode;CamerasCategoryLink;CamerasNavNode
;VariousNavNode;;Various Links;rootNode;HackerNewsNavLink, GitHubNavLink;VariousNavNode
#We create the navigation bar components
INSERT_UPDATE NavigationBarComponent;$contentCV[unique=true];uid[unique=true];navigationNode ⌋
֒→
(\&nodeRef);&componentRef;link(uid,
֒→
$contentCV)
;;ElectronicsNavComponent;ElectronicsNavNode;ElectronicsNavComponent;HomepageNavLink
;;CamerasNavComponent;CamerasNavNode;CamerasNavComponent;CamerasCategoryLink
;;VariousNavComponent;VariousNavNode;VariousNavComponent;HomepageNavLink
#We create the navigation bar collection
INSERT_UPDATE NavigationBarCollectionComponent;$contentCV[unique=true];uid[unique=true];name ⌋
֒→
;components(uid,
֒→
$contentCV);&componentRef
;;NavBarComponent;Navigation Bar Collection Componeent;ElectronicsNavComponent,CamerasNavCom ⌋
ponent,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.orderSplittingServ
66
CHAPTER 5. COMMERCE AND ACCELERATOR
This service contains a list of splitting strategies to apply on a given order. A strategy needs to implement de.hybris.platform.ordersplitting.strategy.SplittingStrategy. The out of the box strategies
are:
• splitByAvailableCount;
• splitByDeliveryMode;
• splitByPoS;
• splitByNamedDeliveryDate;
• splitByEntryDeliveryAddress;
• splitByWarehouse.
Tip 17: Usage
Implement a splitting strategy To implement a new strategy use
de.hybris.platform.ordersplitting.strategy.AbstractSplittingStrategy, this abstract class is 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 and deprecated Promotion Module which was still using
the deprecated Jalo Layer, the new Promotion Engine uses the services layer and is highly flexible.
Warning!
For backward compatibility reasons under SAP Hybris V6.2 both legacy Promotion Module
and new Promotion Engine are available, but all new promotion implementation should be
done using the Promotion Engine.
Promotion Module
Remember this module is deprecated under SAP Hybris V6.2
Promotions can apply at two different levels:
• product promotion
• order promotion
Promotion are implemeted using the Jalo layer. It means that each promotion template would have
its own Jalo implementation. Your implemetation will need to implement either ProductPromotion
or OrderPromotion, both promotion type extends AbstractPromotion. For example, have a look
at the promotions-items.xml file. Here is an extract of the ProductFixedPricePromotion:
5.5. PROMOTION
<itemtype code="ProductFixedPricePromotion"
extends="ProductPromotion"
jaloclass="de.hybris.platform.promotions.jalo.ProductFixedPricePromotion"
autocreate="true"
generate="true">
<attributes>
֒→
֒→
֒→
<attribute
qualifier="productFixedUnitPrice"
autocreate="true"
type="PromotionPriceRowCollectionType">
<description>Fixed price to sell the product at in specific
currencies.</description>
<persistence type="property" />
<modifiers read="true" write="true" search="false" initial="false"
optional="true" partof="true"/>
</attribute>
<attribute qualifier="messageFired" type="localized:java.lang.String">
<description>The message to show when the promotion has
fired.</description>
<modifiers read="true" write="true" optional="true" />
<persistence type="property">
<columntype>
<value>HYBRIS.LONG_STRING</value>
</columntype>
</persistence>
</attribute>
</attributes>
</itemtype>
67
68
CHAPTER 5. COMMERCE AND ACCELERATOR
Now have a look at the class de.hybris.platform.promotions.jalo.ProductFixedPricePromotion:
public class ProductFixedPricePromotion extends GeneratedProductFixedPricePromotion {
private static final Logger LOG = Logger.getLogger(ProductFixedPricePromotion.class);
public ProductFixedPricePromotion() {
}
public void remove(SessionContext ctx) throws ConsistencyCheckException {
...
}
֒→
֒→
֒→
private boolean hasPromotionPriceRowForCurrency(AbstractOrder order,
Collection<PromotionPriceRow> promotionPriceRows) {
...
}
public List<PromotionResult> evaluate(SessionContext ctx, PromotionEvaluationContext
promoContext) {
...
}
public String getResultDescription(SessionContext ctx, PromotionResult promotionResult,
Locale locale) {
...
}
protected void buildDataUniqueKey(SessionContext ctx, StringBuilder builder) {
...
}
protected void deepCloneAttributes(SessionContext ctx, Map values) {
...
}
}
Your promotion implementation extends:
GeneratedProductFixedPricePromotion
ProductPromotion
GeneratedProductPromotion
AbstractPromotion
de.hybris.platform.promotions.jalo.AbstractPromotion defines two abstract methods that all promotions will need to implement :
public abstract List<PromotionResult> evaluate(SessionContext var1,
֒→
PromotionEvaluationContext var2);
public abstract String getResultDescription(SessionContext var1, PromotionResult var2,
֒→
Locale var3);
69
5.5. PROMOTION
The major flaw of this approach and it’s why it is now deprecated, is that you can’t access the
service layer in a trivial manner.
Promotion Engine
Rule Engine
The rule engine is based on [Drools](http://www.drools.org), a Business Rules Management System
(BRMS). It provides a mechanism to define business rules with conditions and actions (for example
if you buy 2 products of the same type you will get a discount of 10
The rule engine is only used by the promotion engine out of the box but it could be useful for
other features that could benefit from a rules/actions engine like the business process framework
used by Hybris or order sourcing or btg.
It is made from two independent components:
• rule builder (accessible from the backoffice, Rule Engine -> Source Rule -> +
Promotion Rule)
• rule processor
Figure 5.6: RuleEngine
Actions and conditions are used to create rules. They are the building blocks of the rule engine.
Rules are compiled using the IR (Intermediate Representation) into executables.
Rule Aware Object
Rule aware objects (RAO) are plain java objects (like java beans) they are used by the rule engine
to determine if a condition is fulfilled or not. When running the rule engine we need to carry data
from the application into the rule context as a set of facts.
Out of the box RAO objects:
• OrderRAO
• CartRAO
• UserRAO
• RuleEngineResultRAO
• DeliveryModeRAO
70
CHAPTER 5. COMMERCE AND ACCELERATOR
RAO objects are defined using beans.xml files, and therefore are generated at compile time, you
can extend existing one or create new one.
Let’s extend de.hybris.platform.ruleengineservices.rao.AbstractOrderRAO with an additional value
dayOfWeek represented by an Integer (from 1 to 7). First we need to update the bean definition:
<bean class="de.hybris.platform.ruleengineservices.rao.AbstractOrderRAO"
֒→
template="resources/coderao-template.vm"
extends="de.hybris.platform.ruleengineservices.rao.AbstractActionedRAO">
<property name="dayOfWeek" type="Integer" />
</bean>
Now we need to create a new populator for our new field :
package de.hybris.ruleenginetrail.converters.populator;
import
import
import
import
de.hybris.platform.core.model.order.AbstractOrderModel;
de.hybris.platform.ruleengineservices.converters.populator.CartRaoPopulator;
de.hybris.platform.ruleengineservices.rao.CartRAO;
de.hybris.platform.servicelayer.dto.converter.ConversionException;
import java.time.LocalDate;
public class ExtendedCartRaoPopulator extends CartRaoPopulator {
֒→
@Override
public void populate(AbstractOrderModel source, CartRAO target) throws
ConversionException {
super.populate(source, target);
target.setDayOfWeek(LocalDate.now().getDayOfWeek().getValue());
}
}
And finally update your spring configuration:
<alias alias="cartRaoPopulator" name="extendedCartRaoPopulator" />
<bean id="extendedCartRaoPopulator"
class="de.hybris.ruleenginetrail.converters.populator.ExtendedCartRaoPopulator"
֒→
parent="defaultCartRaoPopulator" />
71
5.5. PROMOTION
Create a new condition
Warning!
This requires you to have extended the cart rao.
Let’s create a new condition to be fulfilled only on week end days (Saturday and Sunday). First you
need an implementation of de.hybris.platform.ruleengineservices.compiler.RuleConditionTranslator.
package de.hybris.ruleenginetrail.rule.evaluation.conditions.impl;
import
import
import
import
de.hybris.platform.ruleengineservices.compiler.};
de.hybris.platform.ruleengineservices.rao.CartRAO;
de.hybris.platform.ruleengineservices.rule.data.RuleConditionData;
de.hybris.platform.ruleengineservices.rule.data.RuleConditionDefinitionData;
public class RuleCartWeekEndConditionTranslator implements RuleConditionTranslator {
֒→
֒→
@Override
public RuleIrCondition translate(RuleCompilerContext context, RuleConditionData
ruleConditionData, RuleConditionDefinitionData ruleConditionDefinitionData) throws
RuleCompilerException {
final String cartRaoVariable = context.generateVariable(CartRAO.class);
final RuleIrAttributeCondition weekEndDayCondition = new RuleIrAttributeCondition();
weekEndDayCondition.setVariable(cartRaoVariable);
weekEndDayCondition.setAttribute("dayOfWeek");
weekEndDayCondition.setOperator(RuleIrAttributeOperator.GREATER_THAN);
weekEndDayCondition.setValue(Integer.valueOf(5));
return weekEndDayCondition;
}
}
Then you need to create a new Spring bean for your condition:
<alias alias="ruleCartWeekEndConditionTranslator"
֒→
name="defaultRuleCartWeekEndConditionTranslator" />
<bean name="defaultRuleCartWeekEndConditionTranslator" class="de.hybris.ruleenginetrail.rule ⌋
֒→
.evaluation.conditions.impl.RuleCartWeekEndConditionTranslator"
֒→
/>
72
CHAPTER 5. COMMERCE AND ACCELERATOR
Finally creating the new condition and mapping within SAP Hybris :
$lang=en
INSERT_UPDATE RuleConditionDefinition;id[unique=true];name[lang=$lang];priority;breadcrumb[l ⌋
ang=$lang];allowsChildren;translatorId;translatorParameters;categories(id)
֒→
;cart_weekend;Cart week end;301;Cart week end;false;ruleCartWeekEndConditionTranslator;;cart
INSERT_UPDATE RuleConditionDefinitionParameter;definition(id)[unique=true];id[unique=true];p ⌋
֒→
riority;name[lang=$lang];description[lang=$lang];type;value;required[default=true]
#We don’t insert anything here, not need for extra parameters
INSERT_UPDATE RuleConditionDefinitionRuleTypeMapping;definition(id)[unique=true];ruleType(co ⌋
de)[unique=true]
֒→
;cart_weekend;PromotionSourceRule
Warning!
RuleConditionDefinition translatorId must be the Spring bean name.
Update your system, and you should be able to select Cart Week End from the rule builder.
Available conditions
Your translator will return a condition for the rule engine. So the rule engine can compile and
optimize your rules for runtime. Out of the box, you have the following available conditions:
true de.hybris.platform.ruleengineservices.compiler.RuleIrTrueCondition
false de.hybris.platform.ruleengineservices.compiler.RuleIrFalseCondition
condition de.hybris.platform.ruleengineservices.compiler.RuleIrGroupCondition
RuleIrFalseCondition irFalseCondition = new RuleIrFalseCondition();
RuleIrTrueCondition irTrueCondition = new RuleIrTrueCondition();
RuleIrGroupCondition irCondition = new RuleIrGroupCondition();
irCondition.setOperator(RuleIrGroupOperator.OR);
irCondition.setChildren(Arrays.asList(irFalseCondition, irTrueCondition));
exists condition de.hybris.platform.ruleengineservices.compiler.RuleIrExistsCondition
5.5. PROMOTION
73
String productRaoVariable = context.generateVariable(ProductRAO.class);
RuleIrTypeCondition irTypeCondition = new RuleIrTypeCondition();
irTypeCondition.setVariable(productRaoVariable);
RuleIrExistsCondition irCondition = new RuleIrExistsCondition();
irCondition.setChildren(Collections.singletonList(irTypeCondition));
not condition de.hybris.platform.ruleengineservices.compiler.RuleIrNotCondition
String productRaoVariable = context.generateVariable(ProductRAO.class);
RuleIrTypeCondition irTypeCondition = new RuleIrTypeCondition();
irTypeCondition.setVariable(productRaoVariable);
RuleIrNotCondition irCondition = new RuleIrNotCondition();
irCondition.setChildren(Collections.singletonList(irTypeCondition));
type condition de.hybris.platform.ruleengineservices.compiler.RuleIrTypeCondition
String cartRaoVariable = context.generateVariable(CartRAO.class);
RuleIrTypeCondition irCondition = new RuleIrTypeCondition();
irCondition.setVariable(cartRaoVariable);
attribute condition de.hybris.platform.ruleengineservices.compiler.RuleIrAttributeCondition
String cartRaoVariable = context.generateVariable(CartRAO.class);
RuleIrAttributeCondition irCondition = new RuleIrAttributeCondition();
irCondition.setVariable(cartRaoVariable);
irCondition.setAttribute("total");
irCondition.setOperator(RuleIrAttributeOperator.GREATER_THAN_OR_EQUAL);
irCondition.setValue(BigDecimal.valueOf(100));
74
CHAPTER 5. COMMERCE AND ACCELERATOR
Create a new action
Let’s create a new type of action. This will add a discount on the order based on how many
previous orders the customer fullfiled, for example:
A customer A has 3 orders in his history; his new order will be discounted by 3 value factor B with
a maximum of discount of C. First, we need to create a new RAO action:
5.5. PROMOTION
package de.hybris.ruleenginetrail.rule.evaluation.actions.impl;
import com.google.common.base.Preconditions;
import de.hybris.platform.ruleengineservices.rao.};
import de.hybris.platform.ruleengineservices.rule.evaluation.RuleActionContext;
import de.hybris.platform.ruleengineservices.rule.evaluation.actions.AbstractRuleExecutableS ⌋
֒→
upport;
import de.hybris.platform.ruleengineservices.rule.evaluation.actions.RAOAction;
import org.apache.commons.collections.MapUtils;
import java.math.BigDecimal;
import java.util.Map;
import java.util.Optional;
public class RuleOrderHistoryDiscountRAOAction extends AbstractRuleExecutableSupport
֒→
implements RAOAction {
static private String VALUE = "value";
static private String CART_SIZE = "max_discount";
֒→
֒→
֒→
@Override
public void performAction(RuleActionContext context, Map<String, Object> parameters) {
Preconditions.checkArgument(MapUtils.isNotEmpty(parameters), "Properties passed as a
method argument must not be empty");
this.validateRule(context);
final Optional<BigDecimal> value =
this.extractAmountForCurrency(context,parameters.get(VALUE));
final Optional<BigDecimal> maxDiscount =
this.extractAmountForCurrency(context,parameters.get(CART_SIZE));
if(value.isPresent() \&& maxDiscount.isPresent()){
this.performAction(context, value.get(), maxDiscount.get());
}
this.trackRuleGroupExecutions(context);
this.trackRuleExecution(context);
}
֒→
֒→
֒→
֒→
}
protected void performAction(RuleActionContext context, BigDecimal amount, BigDecimal
maxDiscount) {
CartRAO cartRao = context.getCartRao();
final int numOfOrders = cartRao.getUser().getOrders().size();
final BigDecimal calculatedDiscount =
amount.multiply(BigDecimal.valueOf(numOfOrders));
final BigDecimal discount = maxDiscount.compareTo(calculatedDiscount) == 1 ?
calculatedDiscount : maxDiscount;
DiscountRAO discountRao =
this.getRuleEngineCalculationService().addOrderLevelDiscount(cartRao, false, discount);
RuleEngineResultRAO result = context.getRuleEngineResultRao();
result.getActions().add(discountRao);
this.setRAOMetaData(context, new AbstractRuleActionRAO[]{discountRao});
context.updateFacts(new Object[]{cartRao, result});
context.insertFacts(new Object[]{discount});
}
75
76
CHAPTER 5. COMMERCE AND ACCELERATOR
We now need to create create two Spring beans for our new action:
<alias alias="ruleOrderHistoryDiscountRAOAction"
֒→
name="defaultRuleOrderHistoryDiscountRAOAction" />
<bean id="defaultRuleOrderHistoryDiscountRAOAction" parent="abstractRuleExecutableSupport"
class="de.hybris.ruleenginetrail.rule.evaluation.actions.impl.RuleOrderHistoryDiscountR ⌋
֒→
֒→
AOAction"/>
<alias alias="ruleOrderHistoryDiscountAction" name="defaultRuleOrderHistoryDiscountAction" />
<bean id="defaultRuleOrderHistoryDiscountAction"
֒→
class="de.hybris.platform.ruledefinitions.actions.DefaultRuleExecutableAction">
<property name="raoAction" ref="ruleOrderHistoryDiscountRAOAction"/>
</bean>
Warning!
We use DefaultRuleExecutableAction for backward compatibility, see the following topic:
Promotion actions.
Last step is to define the rule action, its parameter and mapping:
$lang=en
INSERT_UPDATE RuleActionDefinition;id[unique=true];name[lang=$lang];priority;breadcrumb[lang ⌋
=$lang];translatorId;translatorParameters;categories(id)
֒→
;order_history_discount;Order percentage discount base on how many orders;1200;Apply
{value}% discount on the multiply by how many orders customer has, max of
֒→
{max_discount}%;ruleExecutableActionTranslator;actionId->ruleOrderHistoryDiscountAction ⌋
֒→
֒→
;cart_discounts
INSERT_UPDATE RuleActionDefinitionParameter;definition(id)[unique=true];id[unique=true];prio ⌋
rity;name[lang=$lang];description[lang=$lang];type;value;required[default=true]
֒→
;order_history_discount;value;1000;Percentage discount value factor;Percentage discount that
֒→
multiplied by order numbers;java.math.BigDecimal;;
;order_history_discount;max_discount;1001;Maximum discount;Max
discount;java.math.BigDecimal;;
֒→
INSERT_UPDATE RuleActionDefinitionRuleTypeMapping;definition(id)[unique=true];ruleType(code) ⌋
֒→
[unique=true]
;order_history_discount;PromotionSourceRule
You can create as many RuleActionDefinitionParameter as you need they would be available from
the backoffice and inside you RAO action parameters map.
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.
5.6. PAYMENT
77
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 (canceled) 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 ongoing 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.
Tip 18: Payment providers
SAP Hybris can have multiple PSP configured at the same time, it’s up to the checkout
flow to give the customer the option to choose the final PSP.
HOP
Out of the box, SAP Hybris provides an example of a hosted order page. A HOP is a page hosted by
the payment provider where the customer will enter all his payment information. In a production
environment the flow would be as follows:
• customer enters the checkout flow;
• customer reaches the payment step and click on pay;
• customer is redirected to the payment provider site where he will enter all required payment
information;
• customer is redirected to SAP Hybris with a uid of his transaction so SAP Hybris can check
that the transaction was successful.
During the entire transaction SAP Hybris didn’t handle any sensitive payment data
from the customer, all SAP Hybris knows is the uid of the transaction
78
CHAPTER 5. COMMERCE AND ACCELERATOR
SOP
Out of the box, SAP Hybris provides an example of a silent order page. A SOP is page hosted by
SAP Hybris with a from sent directly to the payment provider. A SOP can be entirely customized
unlike a HOP (hosted by the payment provider). In a production environment the flow would be
as follows:
• customer enters the checkout flow;
• customer reaches the payment step and click on pay;
• customer fill a form hosted by SAP Hybris but redirecting to the payment provider;
• the payment provider receive the submited form and process the payment;
• customer is redirected to SAP Hybris with a uid of his transaction so SAP Hybris can check
that the transaction was successful.
To host a SOP you need to have a SSL certificate
During the entire transaction SAP Hybris didn’t handle any sensitive payment data
from the customer, all SAP Hybris knows is the uid of the transaction
PCI compliance
The payment card industry security standard enforce strict rules for your platform in order for you
to accept payment by credit card ([What is PCI compliance](http://www.onlinetech.com/resources/references/what
is-pci-compliance)).
In both mocked implementation SAP Hybris will only know a transaction uid, this is great for PCI
compliance
Internationalization
SAP Hybris supports out of the box the following:
• 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:
5.8. REQUEST HANDLING
79
• 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:
![Spring MVC - Request Handling](images/spring-mvc-requesthandling.png)
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 change from your configuration (they are intentionally empty):
hybhubstorefront.webroot=
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
80
CHAPTER 5. COMMERCE AND ACCELERATOR
• customerLocationRestorationFilter
• ....
The filter entry point is configured inside your web application web.xml file:
<filter>
<description>
Spring configured chain of spring filter beans in tenant scope
</description>
<filter-name>storefrontTenantFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
The bean storefrontTenantFilterChain is configured inside your extension spring-filter-config.xml:
<bean id="storefrontTenantFilterChain" class="com.hybhub.storefront.filters.UrlPathFilter" >
<property name="defaultFilter" ref="storefrontTenantDefaultFilterChain"/>
<property name="urlPathHelper">
<bean class="org.springframework.web.util.UrlPathHelper"/>
</property>
<property name="urlPathMapping">
<map>
<entry key="/integration/" value-ref="integrationTenantFilterChain"/>
</map>
</property>
</bean>
Create a new request filter
Create a new class:
5.8. REQUEST HANDLING
package com.hybhub.storefront.filters;
import java.io.IOException;
import
import
import
import
import
javax.servlet.FilterChain;
javax.servlet.ServletException;
javax.servlet.ServletRequest;
javax.servlet.ServletResponse;
javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.filter.GenericFilterBean;
public class HybhubFilter extends GenericFilterBean
{
Logger LOG = LoggerFactory.getLogger(HybhubFilter.class);
֒→
֒→
֒→
@Override
public void doFilter(final ServletRequest paramServletRequest, final ServletResponse
paramServletResponse,
final FilterChain paramFilterChain) throws IOException,
ServletException
{
final HttpServletRequest httpRequest = (HttpServletRequest)
paramServletRequest;
LOG.debug("Request received by the filter " + this.getFilterName());
LOG.debug("Requested path was " + httpRequest.getPathInfo());
paramFilterChain.doFilter(paramServletRequest, paramServletResponse);
}
}
Then update your storefront spring-filter-config.xml file with:
<bean id="hybhubFilter" class="com.hybhub.storefront.filters.HybhubFilter" />
<alias name="defaultStorefrontTenantDefaultFilterChainList"
֒→
alias="storefrontTenantDefaultFilterChainList" />
<util:list id="defaultStorefrontTenantDefaultFilterChainList">
<!-- other filters -->
<ref bean="hybhubFilter"/>
<!-- other filters -->
</util:list>
The order you place your filter matters as they are executed in the list order!
81
82
CHAPTER 5. COMMERCE AND ACCELERATOR
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.
5.9. HOT FOLDERS
83
Create a inbound, outbound, mapping and converter
<file:inbound-channel-adapter id="hybhubBatchFilesCustomer"
֒→
directory="#{baseDirectoryTenant}"
filename-regex="^customers_full\-(.*)-(\d+)\.csv" comparator="fileOrderComparator">
<int:poller fixed-rate="1000" />
</file:inbound-channel-adapter>
<file:outbound-gateway request-channel="hybhubBatchFilesCustomer"
֒→
reply-channel="hybhubBatchFilesCustomerProc"
directory="#{baseDirectoryTenant}/processing" delete-source-files="true" />
<bean id="hybhubCustomersHeaderSetupTask"
֒→
class="de.hybris.platform.acceleratorservices.dataimport.batch.task.HeaderSetupTask">
<property name="catalog" value="electronicsProductCatalog" />
<property name="net" value="false" />
<property name="storeBaseDirectory" ref="baseDirectoryTenant" />
</bean>
<int:service-activator input-channel="hybhubBatchFilesCustomerProc"
֒→
output-channel="batchFilesHeaderInit"
ref="hybhubCustomersHeaderSetupTask" method="execute" />
<bean id="hybhubBatchCustomerConverterMapping"
class="de.hybris.platform.acceleratorservices.dataimport.batch.converter.mapping.i ⌋
mpl.DefaultConverterMapping"
֒→
p:mapping="customers_full"
p:converter-ref="hybhubBatchCustomerConverter"/>
<bean id="hybhubBatchCustomerConverter" class="de.hybris.platform.acceleratorservices.dataim ⌋
֒→
port.batch.converter.impl.DefaultImpexConverter">
<property name="header">
<value>#{defaultImpexProductHeader}
# Insert Customer
\$defaultPassword=1234
\$setName=name[cellDecorator=de.hybris.platform.acceleratorservices. ⌋
֒→
dataimport.batch.decorator.CustomerNameDecorator]
INSERT_UPDATE Customer;uid[unique=true];\$setName;title(code);sessio ⌋
֒→
nLanguage(isocode);sessionCurrency(isocode);groups(uid)
</value>
</property>
<property name="impexRow">
<value>;{+0};{1} {2};{3};{4};{5};{6}</value>
</property>
</bean>
Here we are using headerInitTask as a batchFilesHeaderInit. This is expecting your file to match
the following pattern to extract the language code:
-(\w{2})-(\d+)\.csv
84
CHAPTER 5. COMMERCE AND ACCELERATOR
And this to extract the sequence:
-(\d+)\.csv
Create a file under data/acceleratorservices/import/master named customers_full-en-0.csv with
the following content :
serge.d@hybhub.com,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
Figure 5.7: Data model
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:
5.10. DATA MODELING
85
<coremodule generated="true"
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
:
86
CHAPTER 5. COMMERCE AND ACCELERATOR
<?xml version="1.0" encoding="ISO-8859-1"?>
<!-~ [y] hybris Platform
~
~ Copyright (c) 2000-2016 SAP SE
~ All rights reserved.
~
~ This software is the confidential and proprietary information of SAP
~ Hybris ("Confidential Information"). You shall not disclose such
~ Confidential Information and shall use it only in accordance with the
~ terms of the license agreement you entered into with SAP Hybris.
-->
<!-ATTENTION: This is just an example file. You have to edit it according to your needs.
-->
<items
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="items.xsd">
<itemtypes>
<!-<itemtype generate="true"
code="MyProduct"
jaloclass="yemptypackage.jalo.MyProduct"
extends="Product"
autocreate="true"
>
֒→
֒→
<attributes>
<attribute qualifier="myExampleInitialStringField"
type="java.lang.String">
<description>My Example Initial String
Value</description>
<modifiers initial="true"/>
<persistence type="property"/>
</attribute>
<attribute qualifier="myExampleBooleanField"
֒→
֒→
type="java.lang.Boolean">
<description>Example Initial Boolean
Field</description>
<persistence type="property"/>
</attribute>
<attribute qualifier="media" type="Media">
<persistence type="property"/>
</attribute>
</attributes>
</itemtype>
-->
</itemtypes>
</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
5.10. DATA MODELING
87
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 :
<atomictype class="java.lang.Double" extends="java.lang.Number" autocreate="true"
generate="false"/>
• Collection types, contains a typed number of instances. This can be a Collection (Unordered),
a List (Ordered) or a Set (Unique) of elements. The collection is kept in the database by
saving a csv list of instance pks.
For Example if I create a wish list set of Products for Customers :
<collectiontypes>
<collectiontype code="ProductSet" elementtype="Product" type="set" autocreate="true"
֒→
generate="true" />
</collectiontypes>
<itemtypes>
<itemtype code="Customer" autocreate="false" generate="false">
<attributes>
<attribute qualifier="wishList" type="ProductSet">
<persistence type="property"/>
</attribute>
</attributes>
</itemtype>
</itemtypes>
After updating my system the User table would look like this:
|p_wishlist|text|YES||NULL||
If I query a Customer who has 3 products in his wish list :
mysql> select p_uid, p_wishlist from users where p_uid = "hybris";
+--------+------------------------------------------------+
|
| p_uid | p_wishlist
+--------+------------------------------------------------+
| ,#2,8796093087745,8796093120513,8796093054977, |
| user
+--------+------------------------------------------------+
1 row in set (0.00 sec)
88
CHAPTER 5. COMMERCE AND ACCELERATOR
You can see the size of the Set (3) and the 3 Products PKs.
Use relation types whenever possible, collection types have severe limitation (maximum length as for example in Mysql maximum text size is 65,535 characters, not
cached by Hybris).
• 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
:
<enumtype code="OrderStatus" autocreate="true" generate="true" dynamic="true">
<value code="CREATED"/>
<value code="ON_VALIDATION"/>
<value code="COMPLETED"/>
<value code="CANCELLED"/>
</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 :
<maptype code="localized:java.lang.String"
argumenttype="Language"
returntype="java.lang.String"
autocreate="true"
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 :
<relation code="Country2RegionRelation" generate="true" localized="false" autocreate="true">
<sourceElement type="Country" qualifier="country" cardinality="one">
<modifiers read="true" write="true" search="true" optional="false" unique="true"/>
</sourceElement>
<targetElement type="Region" qualifier="regions" cardinality="many">
<modifiers read="true" write="true" search="true" partof="true"/>
</targetElement>
</relation>
5.10. DATA MODELING
89
• 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. The following is an example extracted from core-items.xml:
<itemtype code="Title"
extends="GenericItem"
jaloclass="de.hybris.platform.jalo.user.Title"
autocreate="true"
generate="true">
<!-- deployment="de.hybris.platform.persistence.user.Title" -->
<deployment table="Titles" typecode="24"/>
<attributes>
<attribute autocreate="true" qualifier="code" type="java.lang.String">
<persistence type="property"/>
<modifiers read="true" write="true" search="true" initial="true"
֒→
optional="false" unique="true"/>
<custom-properties>
<property name="hmcIndexField">
<value>"thefield"</value>
</property>
</custom-properties>
</attribute>
<attribute autocreate="true" qualifier="name" type="localized:java.lang.String">
<modifiers read="true" write="true" search="true" optional="true"/>
<persistence type="property"/>
<custom-properties>
<property name="hmcIndexField">
<value>"thefield"</value>
</property>
</custom-properties>
</attribute>
</attributes>
<indexes>
<index name="codeIdx">
<key attribute="code"/>
</index>
</indexes>
</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 post can have comments linked to users.
First we need enum types :
• for post status (draft, published, deleted)
• for comment status (pending, approved, blocked)
90
CHAPTER 5. COMMERCE AND ACCELERATOR
Figure 5.8: UML blog
<enumtypes>
<enumtype code="PostStatus">
<value code="DRAFT"/>
<value code="PUBLISHED"/>
<value code="DELETED"/>
</enumtype>
<enumtype code="CommentStatus">
<value code="PENDING"/>
<value code="APPROVED"/>
<value code="BLOCKED"/>
</enumtype>
</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)
[ycheckdeployments] No deployment defined for non-abstract itemType Blog in file:
/Users/b.vanalderweireldt/.../resources/hybhubaddon-items.xml
5.10. DATA MODELING
<itemtypes>
<itemtype code="Blog" extends="GenericItem" autocreate="true" generate="true">
<deployment table="blog" typecode="11001" />
<attributes>
<attribute qualifier="code" type="java.lang.String">
<modifiers initial="true" read="true" write="false"
֒→
optional="false" unique="true" />
<persistence type="property" />
</attribute>
<attribute qualifier="active" type="boolean">
<persistence type="property" />
</attribute>
</attributes>
</itemtype>
֒→
<itemtype code="Post" extends="GenericItem" autocreate="true" generate="true">
<deployment table="post" typecode="11002" />
<attributes>
<attribute qualifier="blog" type="Blog">
<persistence type="property"/>
</attribute>
<attribute qualifier="date" type="java.util.Date">
<modifiers optional="false"/>
<persistence type="property" />
</attribute>
<attribute qualifier="author" type="Employee">
<modifiers optional="false"/>
<persistence type="property" />
</attribute>
<attribute qualifier="title" type="localized:java.lang.String">
<persistence type="property" />
</attribute>
<attribute qualifier="content" type="localized:java.lang.String">
<persistence type="property">
<columntype>
<value>HYBRIS.LONG_STRING</value>
</columntype>
</persistence>
<modifiers search="false"/>
</attribute>
<attribute qualifier="keywords" type="StringCollection">
<persistence type="property" />
</attribute>
<attribute qualifier="status" type="PostStatus">
<persistence type="property" />
<defaultvalue>em().getEnumerationValue("PostStatus",
"DRAFT")</defaultvalue>
</attribute>
</attributes>
</itemtype>
<itemtype code="PostComment" extends="GenericItem" autocreate="true" generate="true">
<deployment table="postcomment" typecode="11003" />
<attributes>
<attribute qualifier="author" type="User">
<persistence type="property"/>
</attribute>
<attribute qualifier="content" type="java.lang.String">
<persistence type="property">
<columntype>
<value>HYBRIS.LONG_STRING</value>
</columntype>
</persistence>
<modifiers search="false" optional="false"/>
</attribute>
<attribute qualifier="status" type="CommentStatus">
<persistence type="property" />
</attribute>
</attributes>
</itemtype>
</itemtypes>
91
92
CHAPTER 5. COMMERCE AND ACCELERATOR
We finally need to create relations between Blog and CMSSIte.
<relation localized="false" code="BlogCMSSiteRelation">
<deployment table="blogcmssiterelation" typecode="1201"/>
<sourceElement type="Blog" qualifier="blogs" cardinality="many"/>
<targetElement type="CMSSite" qualifier="sites" cardinality="many"/>
</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 as 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):
![Backoffice types](images/backoffice-types.png)
We can see that all newly defined items are available in our current system.
Import test data
INSERT_UPDATE Blog;code[unique=true];active[default=true]
;myBlog;
INSERT_UPDATE Post;date[unique=true][dateformat=dd-MM-yyyy];Blog(code);author(uid)
;01-01-2016;myBlog;admin
INSERT_UPDATE PostComment;content[unique=true];author(uid);status(code);
;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
features 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:
5.10. DATA MODELING
93
• Users will have a birthday attribute
• Products will have a boolean to activate (or not) an export to Google Shopping
<itemtype code="Product" autocreate="false" generate="false">
<attributes>
<attribute qualifier="exportToGoogleShopping" type="java.lang.Boolean">
<persistence type="property"/>
</attribute>
</attributes>
</itemtype>
<itemtype code="Customer" autocreate="false" generate="false">
<attributes>
<attribute qualifier="birthday" type="java.util.Date">
<persistence type="property"/>
</attribute>
</attributes>
</itemtype>
Update your system and check from the backoffice that new attributes have been added to your
types:
![Product new attribute](images/backoffice-product-newAttr.png)
![Customer new attribute](images/backoffice-customer-newAttr.png)
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:
<attribute autocreate="true" qualifier="name" type="localized:java.lang.String">
<modifiers read="true" write="true" search="true" optional="true"/>
<persistence type="property"/>
<custom-properties>
<property name="hmcIndexField">
<value>"thefield"</value>
</property>
</custom-properties>
</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 :
94
CHAPTER 5. COMMERCE AND ACCELERATOR
MariaDB [database]> explain productslp;
+-----+--------------+------+-----+---------+-------+
| Type
| Null
| Field
+-----+--------------+------+-----+---------+-------+
| ITEMPK
| bigint(20)
| NO
| bigint(20)
| YES
| ITEMTYPEPK
| bigint(20)
| NO
| LANGPK
| p_name
| varchar(255) | YES
| text
| YES
| p_description
| p_manufacturertypedescription | varchar(255) | YES
| p_segment
| varchar(255) | YES
| longblob
| YES
| p_articlestatus
| text
| YES
| p_summary
| p_directionofuse
| text
| YES
| text
| YES
| p_specialpricedescription
| varchar(255) | YES
| p_style
| p_size
| varchar(255) | YES
| varchar(255) | YES
| p_color
+-----+--------------+------+-----+---------+-------+
14 rows in set (0.01 sec)
| Key | Default | Extra |
| PRI | 0
|
| NULL
| PRI | 0
|
| NULL
|
| NULL
|
| NULL
|
| NULL
|
| NULL
|
| NULL
|
| NULL
|
| NULL
|
| NULL
|
| NULL
|
| NULL
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Each localized attribute of an item is grouped in this table and linked to a language through
LANGPK.
The model service will create getters and setters like this :
/**
* <i>Generated method</i> - Getter of the <code>Product.description</code> attribute
defined at extension <code>core</code>.
֒→
* @return the description
*/
@Accessor(qualifier = "description", type = Accessor.Type.GETTER)
public String getDescription()
{
return getDescription(null);
}
/**
* <i>Generated method</i> - Getter of the <code>Product.description</code> attribute
defined at extension <code>core</code>.
֒→
* @param loc the value localization key
* @return the description
* @throws IllegalArgumentException if localization key cannot be mapped to data language
*/
@Accessor(qualifier = "description", type = Accessor.Type.GETTER)
public String getDescription(final Locale loc)
{
return getPersistenceContext().getLocalizedValue(DESCRIPTION, loc);
}
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).
5.10. DATA MODELING
95
Create a localized attribute
localized attributes are maps, they are declared under core-items.xml :
<maptype code="localized:java.lang.String"
argumenttype="Language"
returntype="java.lang.String"
autocreate="true"
generate="false"/>
<maptype code="localized:java.lang.Integer"
argumenttype="Language"
returntype="java.lang.Integer"
autocreate="true"
generate="false"/>
<maptype code="localized:java.lang.Boolean"
argumenttype="Language"
returntype="java.lang.Boolean"
autocreate="true"
generate="false"/>
....
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 lets say you need to localize groups :
<maptype code="localized:Group"
argumenttype="Language"
returntype="UserGroup"
autocreate="true"
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:
96
CHAPTER 5. COMMERCE AND ACCELERATOR
<enumtype code="OrderStatus" autocreate="true" generate="true" dynamic="true">
<value code="CREATED"/>
<value code="ON_VALIDATION"/>
<value code="COMPLETED"/>
<value code="CANCELLED"/>
</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
:
<enumtype code="OrderStatus" autocreate="false" generate="false" dynamic="true">
<value code="MYSTATUS"/>
</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) :
import de.hybris.platform.enumeration.EnumerationService;
import de.hybris.platform.core.enums.OrderStatus;
EnumerationService es = spring.getBean("enumerationService");
OrderStatus os = es.getEnumerationValue("ORDERSTATUS", "MYSTATUS");
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
5.10. DATA MODELING
97
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 not 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 and not 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..." :
<itemtype code="PostComment" extends="GenericItem" autocreate="true" generate="true">
<deployment table="postcomment" typecode="11003" />
<attributes>
<attribute qualifier="author" type="User">
<persistence type="property"/>
</attribute>
<attribute qualifier="content" type="java.lang.String">
<persistence type="property">
<columntype>
<value>HYBRIS.LONG_STRING</value>
</columntype>
</persistence>
<modifiers search="false" optional="false"/>
</attribute>
<attribute qualifier="status" type="CommentStatus">
<persistence type="property" />
</attribute>
<attribute qualifier="summary" type="java.lang.String">
<persistence type="dynamic"
֒→
attributeHandler="dynamicAttributesPostCommentSummaryHandler"/>
</attribute>
</attributes>
</itemtype>
Attribute Handler value is the name of the Spring bean that is responsible for the
dynamic attribute.
98
CHAPTER 5. COMMERCE AND ACCELERATOR
Next step is to create the class to handle the dynamic attribute, we will call it ‘DynamicAttributesPostCommentSummaryHandler’:
package com.hybhub.hybhubaddon.servicelayer.dynamicattributes;
import de.hybris.platform.servicelayer.model.attribute.DynamicAttributeHandler;
import com.hybhub.hybhubaddon.model.PostCommentModel;
public class DynamicAttributesPostCommentSummaryHandler implements
֒→
DynamicAttributeHandler<String, PostCommentModel>
{
final static String SEP = " - ";
final static int MAX_CONTENT = 100;
֒→
֒→
@Override
public String get(final PostCommentModel postComment)
{
final StringBuilder sb = new
StringBuilder(postComment.getStatus().getCode());
sb.append(SEP);
sb.append(postComment.getAuthor().getDisplayName());
sb.append(SEP);
sb.append(postComment.getContent().length() > MAX_CONTENT ?
postComment.getContent().substring(0, MAX_CONTENT)
: postComment.getContent());
return sb.toString();
}
@Override
public void set(final PostCommentModel postComment, final String str)
{
throw new IllegalAccessError("Cannot set that attribute [Summary]");
}
}
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 throw an exception if the setter is used.
Next step is to register this newly created class in a bean context:
<bean id="dynamicAttributesPostCommentSummaryHandler" class="com.hybhub.hybhubaddon.servicel ⌋
ayer.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/ :
5.10. DATA MODELING
import
import
import
import
import
99
com.hybhub.hybhubaddon.model.PostCommentModel
de.hybris.platform.servicelayer.model.ModelService
de.hybris.platform.servicelayer.search.FlexibleSearchService
java.util.List
de.hybris.platform.servicelayer.user.UserService
UserService us = spring.getBean("userService")
ModelService ms = spring.getBean("modelService")
FlexibleSearchService fss = spring.getBean("flexibleSearchService")
PostCommentModel pcm = ms.create(PostCommentModel.class)
pcm.setAuthor(us.getAdminUser())
List<PostCommentModel> pcms = fss.getModelsByExample(pcm)
println pcms.get(0).getSummary()
If you open the output tab you should see : PENDING - Administrator - This is the content of
the PostComment
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 needs 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 <RELATIONNAME> in file:
<FILENAME> 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:
100
CHAPTER 5. COMMERCE AND ACCELERATOR
<itemtype code="Blog" extends="GenericItem" autocreate="true" generate="true">
<deployment table="blog" typecode="11001" />
...
</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 keys (composite indices), here is an example of an index on the blog type:
<indexes>
<index name="blogIDX" unique="true">
<key attribute="code" lower="true"/>
<key attribute="active"/>
</index>
</indexes>
SAP Hybris will run the following SQL command (may vary upon the targeted database, here we
use HSQL):
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 :
5.10. DATA MODELING
101
<database-schema database="mysql" primary-key="primary key" null="" not-null="not null" >
<type-mapping type="java.lang.String" persistence-type="varchar(255)" />
<type-mapping type="String" persistence-type="varchar(255)" />
<type-mapping
<type-mapping
<type-mapping
<type-mapping
<type-mapping
<type-mapping
<type-mapping
<type-mapping
type="java.lang.Float" persistence-type="float(20,5)" />
type="java.lang.Double" persistence-type="double" />
type="java.lang.Byte" persistence-type="smallint" />
type="java.lang.Character" persistence-type="smallint" />
type="java.lang.Short" persistence-type="integer" />
type="java.lang.Boolean" persistence-type="tinyint(1)" />
type="java.lang.Long" persistence-type="bigint" />
type="java.lang.Integer" persistence-type="integer" />
<type-mapping
<type-mapping
<type-mapping
<type-mapping
<type-mapping
<type-mapping
<type-mapping
<type-mapping
type="float" persistence-type="float(20,5) DEFAULT 0" />
type="double" persistence-type="double DEFAULT 0" />
type="byte" persistence-type="smallint DEFAULT 0" />
type="char" persistence-type="smallint DEFAULT 0" />
type="short" persistence-type="integer DEFAULT 0" />
type="boolean" persistence-type="tinyint(1) DEFAULT 0" />
type="long" persistence-type="bigint DEFAULT 0" />
type="int" persistence-type="integer DEFAULT 0" />
<type-mapping type="java.util.Date" persistence-type="datetime" />
<type-mapping type="java.math.BigDecimal" persistence-type="DECIMAL(30,8)" />
<type-mapping type="java.io.Serializable" persistence-type="LONGBLOB" />
<type-mapping type="HYBRIS.LONG_STRING" persistence-type="TEXT" />
<type-mapping type="HYBRIS.COMMA_SEPARATED_PKS" persistence-type="TEXT" />
<type-mapping type="HYBRIS.PK" persistence-type="BIGINT" />
</database-schema>
To see what commands SAP Hybris uses to create your item types you can use the dry-run
functionality ([Dry Run](http://localhost:9001/platform/dryrun)), for example for our Post type
on HSQL SAP Hybris will execute :
102
CHAPTER 5. COMMERCE AND ACCELERATOR
CREATE CACHED TABLE post
(
hjmpTS BIGINT,
createdTS TIMESTAMP,
modifiedTS TIMESTAMP,
TypePkString BIGINT,
OwnerPkString BIGINT,
PK BIGINT NOT NULL,
p_blog BIGINT,
p_date TIMESTAMP,
p_author BIGINT,
p_keywords LONGVARBINARY,
p_status BIGINT,
aCLTS BIGINT DEFAULT 0,
propTS BIGINT DEFAULT 0,
PRIMARY KEY (PK)
);
CREATE CACHED TABLE postlp
(
ITEMPK BIGINT,
ITEMTYPEPK BIGINT,
LANGPK BIGINT,
p_title NVARCHAR(255),
p_content LONGVARCHAR,
PRIMARY KEY (ITEMPK, LANGPK)
);
Flexible Search Query
FSQL or flexible search query language helps you looking for items and types using a SQL-like
syntax. Why is SAP Hybris 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 needs to have a database abstraction layer, allowing you to write a FSQL query that
would run on any compatible database (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).
Warning!
Flexible Search Queries are only for search, they cannot do any SQL DML or SQL DDL
queries.
Warning!
Flexible Search Queries are executed on the database trough a SQL query, therefore it is
not possible to execute flexible search queries on Jalo or dynamic attributes.
5.11. FLEXIBLE SEARCH QUERY
103
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:
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
Do not get flexible search query restrictions mixed up with CMS restrictions ! On is
only adding filters in the SQL where clause while the other has its own java implementation.
Restrictions are manageable from the SearchRestrictionService:
104
CHAPTER 5. COMMERCE AND ACCELERATOR
package de.hybris.platform.search.restriction;
import
import
import
import
import
de.hybris.platform.core.model.security.PrincipalModel;
de.hybris.platform.core.model.type.ComposedTypeModel;
de.hybris.platform.core.model.type.SearchRestrictionModel;
de.hybris.platform.search.restriction.session.SessionSearchRestriction;
java.util.Collection;
public interface SearchRestrictionService
{
void addSessionSearchRestrictions(Collection<SessionSearchRestriction> arg0);
void addSessionSearchRestrictions(SessionSearchRestriction... arg0);
void clearSessionSearchRestrictions();
void disableSearchRestrictions();
void enableSearchRestrictions();
Collection<SearchRestrictionModel> getActiveSearchRestrictions(PrincipalModel arg0,
֒→
boolean arg1,
Collection<ComposedTypeModel> arg2);
Collection<SearchRestrictionModel> getInactiveSearchRestrictions(PrincipalModel
֒→
arg0, boolean arg1,
Collection<ComposedTypeModel> arg2);
Collection<SearchRestrictionModel> getSearchRestrictions(PrincipalModel arg0,
֒→
boolean arg1,
Collection<ComposedTypeModel> arg2);
Collection<SearchRestrictionModel> getSearchRestrictionsForType(ComposedTypeModel
arg0);
֒→
Collection<SessionSearchRestriction> getSessionSearchRestrictions();
Collection<SessionSearchRestriction> getSessionSearchRestrictions(ComposedTypeModel
֒→
arg0);
boolean hasRestrictions(PrincipalModel arg0, boolean arg1, ComposedTypeModel arg2);
boolean isSearchRestrictionsEnabled();
void removeSessionSearchRestrictions(Collection<SessionSearchRestriction> arg0);
void removalAllSessionSearchRestrictions();
}
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:
INSERT_UPDATE SearchRestriction;code[unique=true];name[lang=en];query;principal(UID);restric ⌋
tedType(code);active;generate
֒→
;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):
5.11. FLEXIBLE SEARCH QUERY
105
select {name} from {Language}
SAP Hybris will execute this SQL query (pay attention to the WHERE clause where our restriction
is added:
SELECT lp_t0.p_name FROM languages item_t0 JOIN languageslp lp_t0
ON item_t0.PK = lp_t0.ITEMPK AND lp_t0.LANGPK =?
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:
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
106
CHAPTER 5. COMMERCE AND ACCELERATOR
• 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 :
SELECT {p:PK}
FROM {Product AS p}
WHERE {p:description[en]:o} LIKE ’%text%’
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
select * from {User}
Category by catalog version
select {c:pk} from {Category as c} where{c:catalogVersion}=?catalogVersion
All Users ordered by desc name
select {name[en]} from {User} order by {name} DESC
Select distinct products
select distinct {name[en]} from {Product} order by {name[en]} asc
Select products and order them by price
5.11. FLEXIBLE SEARCH QUERY
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
select {name[en]}, {OnlineDate} from {Product} where {code} in ( {{ select {code} from
֒→
{Product} where {OnlineDate} > ’2016-01-01 00:00:00.0’ }} )
Tip 19: Usage
You can test all flexible search queries directly from the HAC.
Flexible Search Service
package de.hybris.platform.servicelayer.search;
import
import
import
import
import
import
import
de.hybris.platform.core.model.ItemModel;
de.hybris.platform.servicelayer.search.FlexibleSearchQuery;
de.hybris.platform.servicelayer.search.RelationQuery;
de.hybris.platform.servicelayer.search.SearchResult;
de.hybris.platform.servicelayer.search.TranslationResult;
java.util.List;
java.util.Map;
public interface FlexibleSearchService
{
<T> T getModelByExample(T arg0);
<T> List<T> getModelsByExample(T arg0);
<T> SearchResult<T> search(FlexibleSearchQuery arg0);
<T> SearchResult<T> search(String arg0);
<T> SearchResult<T> search(String arg0, Map<String, ? extends Object> arg1);
<T> SearchResult<T> searchRelation(ItemModel arg0, String arg1, int arg2, int arg3);
<T> SearchResult<T> searchRelation(RelationQuery arg0);
<T> T searchUnique(FlexibleSearchQuery arg0);
TranslationResult translate(FlexibleSearchQuery arg0);
}
107
108
CHAPTER 5. COMMERCE AND ACCELERATOR
Create a Flexible Search query
import
import
import
import
de.hybris.platform.servicelayer.search.FlexibleSearchService
de.hybris.platform.servicelayer.search.FlexibleSearchQuery
de.hybris.platform.servicelayer.search.SearchResult
de.hybris.platform.core.model.product.ProductModel
FlexibleSearchService fsqs = spring.getBean("flexibleSearchService")
String q = "select {code[en]} from {Product} where {code[ANY]} like ?code"
FlexibleSearchQuery myFlexibleSearchQuery = new FlexibleSearchQuery(q)
myFlexibleSearchQuery.addQueryParameter(’code’, ’109%’)
SearchResult result = fsqs.<ProductModel>search(myFlexibleSearchQuery)
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.
5.12. PRODUCT VARIANTS & CATEGORY VARIANTS
109
<enumtypes>
<enumtype code="ScreenSize">
<value code="THIRTEEN" />
<value code="FOURTEEN" />
<value code="FIFTEEN" />
</enumtype>
</enumtypes>
<itemtypes>
<itemtype code="Laptop" extends="Product" autocreate="true" generate="true">
<attributes>
<attribute qualifier="ScreenSize" type="ScreenSize">
<persistence type="property" />
</attribute>
</attributes>
</itemtype>
<itemtype code="LaptopVariant" extends="VariantProduct" autocreate="true"
generate="true"
jaloclass="com.hybhub.jalo.LaptopVariant">
<attributes>
<attribute qualifier="diskCapacity" type="int"
֒→
metatype="VariantAttributeDescriptor">
<persistence type="property"/>
</attribute>
</attributes>
</itemtype>
</itemtypes>
֒→
To mark an attribute as a variant descriptor, you need to use metatype="VariantAttributeDescriptor"
This has one 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.
<itemtype code="LaptopVariant" extends="VariantProduct" autocreate="true" generate="true"
jaloclass="com.hybhub.jalo.Car">
<attributes>
<attribute qualifier="diskCapacity" type="int"
֒→
metatype="VariantAttributeDescriptor">
<persistence type="property"/>
</attribute>
<attribute qualifier="ScreenSize" type="ScreenSize">
<persistence type="property" />
</attribute>
</attributes>
</itemtype>
This is a bad idea, since it is described on the variant level, you need to define a screen size for all
110
CHAPTER 5. COMMERCE AND ACCELERATOR
your variants, even if they all have the same.
Why not define 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:
Figure 5.9: Product Variant Diagram
Category Variants
A different approach is to build category variants with specific attributes. For example our laptop
category has a screen size attribute:
<itemtype code="LaptopCategory" extends="VariantValueCategory">
<attributes>
<attribute qualifier="ScreenSize" type="ScreenSize">
<persistence type="property" />
</attribute>
</attributes>
</itemtype>
<itemtype code="LaptopVariant" extends="VariantProduct" autocreate="true" generate="true">
<attributes>
<attribute qualifier="diskCapacity" type="int"
֒→
metatype="VariantAttributeDescriptor">
<persistence type="property"/>
</attribute>
</attributes>
</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
5.13. CLASSIFICATION ATTRIBUTES
111
$productCatalog=electronicsProductCatalog
$productCatalogName=Electronics Product Catalog
$catalogVersion=catalogversion(catalog(id[default=$productCatalog]),version[default=’Staged’ ⌋
])[unique=true,default=$productCatalog:Staged]
֒→
$supercategories=supercategories(code, $catalogVersion)
$baseProduct=baseProduct(code,$catalogVersion)
$approved=approvalstatus(code)[default=’check’]
# Insert Categories
INSERT_UPDATE LaptopCategory;code[unique=true];name[lang=en];ScreenSize(code);$supercategori ⌋
֒→
es;$catalogVersion
;000100;Laptop;THIRTEEN;1
;000101;Laptop;FIFTEEN;1
INSERT_UPDATE Product;code[unique=true];$supercategories;manufacturerName;manufacturerAID;un ⌋
֒→
it(code);variantType(code);$catalogVersion;$approved
;000010;000100;Apple;MBP-13;pieces;LaptopVariant
;000011;000100;Apple;MBP-15;pieces;LaptopVariant
INSERT_UPDATE LaptopVariant;code[unique=true];$baseProduct;unit(code);diskCapacity;approvals ⌋
tatus(code)[default=’approved’];$catalogVersion
֒→
;000100_256;000010;pieces;256;
;000100_512;000010;pieces;512;
;000101_256;000011;pieces;256;
;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 gives 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 :
112
CHAPTER 5. COMMERCE AND ACCELERATOR
$productCatalog=electronicsProductCatalog
$productCatalogName=Electronics Product Catalog
$catalogVersion=catalogversion(catalog(id[default=$productCatalog]),version[default=’Staged’ ⌋
])[unique=true,default=$productCatalog:Staged]
֒→
$classCatalogVersion=catalogversion(catalog(id[default=’ElectronicsClassification’]),version ⌋
[default=’1.0’])[unique=true,default=’ElectronicsClassification:1.0’]
֒→
$classSystemVersion=systemVersion(catalog(id[default=’ElectronicsClassification’]),version[d ⌋
֒→
efault=’1.0’])[unique=true]
$class=classificationClass(ClassificationClass.code,\$classCatalogVersion)[unique=true]
$supercategories=supercategories(code, $catalogVersion)
$supercategoriesRel=source(code, $classCatalogVersion)[unique=true]
$categories=target(code, $catalogVersion)[unique=true]
$attribute=classificationAttribute(code,$classSystemVersion)[unique=true]
$unit=unit(code,$classSystemVersion)
$approved=approvalstatus(code)[default=’check’]
$baseProduct=baseProduct(code,$catalogVersion)
$clAttrModifiers=system=’ElectronicsClassification’,version=’1.0’,translator=de.hybris.platf ⌋
֒→
orm.catalog.jalo.classification.impex.ClassificationAttributeTranslator,lang=en
# Insert Classifications
INSERT_UPDATE ClassificationClass;$classCatalogVersion;code[unique=true];name[lang=en];allow ⌋
֒→
edPrincipals(uid)[default=’customergroup’]
;;2002;Laptop
# Insert Classification Attributes
INSERT_UPDATE ClassificationAttribute;$classSystemVersion;code[unique=true];name[lang=en]
;;screen size;Screen Size
INSERT_UPDATE ClassAttributeAssignment;$class;$attribute;position;$unit;attributeType(code[d ⌋
efault=string]);multiValued[default=false];range[default=false];localized[default=false]
֒→
;2002;screen size;1;16;number;false;false
INSERT_UPDATE CategoryCategoryRelation;$categories;$supercategoriesRel
;1;2002
$feature1=@screen size[$clAttrModifiers];
INSERT_UPDATE Product;code[unique=true];$supercategories;manufacturerName;manufacturerAID;un ⌋
it(code);variantType(code);$feature1;$catalogVersion;$approved
֒→
;000010;1;Apple;MBP-13;pieces;LaptopVariant;13
;000011;1;Apple;MBP-15;pieces;LaptopVariant;15
INSERT_UPDATE LaptopVariant;code[unique=true];$baseProduct;unit(code);diskCapacity;approvals ⌋
֒→
tatus(code)[default=’approved’];$catalogVersion
;000100_256;000010;pieces;256;
;000100_512;000010;pieces;512;
;000101_256;000011;pieces;256;
;000101_512;000011;pieces;512;
The same product could be classified from two different classification trees ! It offers a lot of
flexibility and it can be modified without changing the SAP Hybris model type!
Chapter 6
Order management
113
114
CHAPTER 6. ORDER MANAGEMENT
Through this chapter, you will learn how to work with orders within a SAP Hybris e-commerce
system.
Business process
SAP Hybris has an out-of-the-box "process engine" (yacceleratorfulfilmentprocess extension). Business processes help you define a list of actions that depend on another, and terminate with a status
that decides the action, which will follow. For example, the first steps of the order-process.xml business process is as follow :
![Order Business Process](images/order-business-process.png)
Let’s create our own business process. We won’t do anything else to create a few actions. First we
need to define our business process:
<itemtype code="MyProcess" autocreate="true" generate="true" extends="BusinessProcess">
<attributes>
<attribute qualifier="fail" type="boolean">
<persistence type="property" />
</attribute>
<attribute qualifier="error" type="boolean">
<persistence type="property" />
</attribute>
</attributes>
</itemtype>
You now need to define your process, create a new file named myprocess-process.xml under /resources/hybhubaddon/process/, my extension is hybhubaddon :
6.1. BUSINESS PROCESS
<?xml version="1.0" encoding="utf-8"?>
<process xmlns="http://www.hybris.de/xsd/processdefinition" start="firstStep"
֒→
name="myProcess" processClass="com.hybhub.hybhubaddon.model.MyProcessModel">
<action id="firstStep" bean="firstStepAction">
<transition name="OK" to="secondStep"/>
<transition name="NOK" to="abortStep"/>
</action>
<action id="secondStep" bean="secondStepAction">
<transition name="OK" to="success"/>
<transition name="NOK" to="error"/>
</action>
<action id="abortStep" bean="abortStepAction">
<transition name="OK" to="failed"/>
</action>
<end id="error" state="ERROR">All went wrong.</end>
<end id="failed" state="FAILED">Couldn’t run the process.</end>
<end id="success" state="SUCCEEDED">All good.</end>
</process>
There are 4 different types of nodes:
• Wait nodes - wait for a subprocess or an external process result;
• Notify nodes - inform a user or user group about 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
115
116
CHAPTER 6. ORDER MANAGEMENT
package com.hybhub.hybhubaddon.actions.myprocess;
import de.hybris.platform.processengine.action.AbstractSimpleDecisionAction;
import de.hybris.platform.task.RetryLaterException;
import com.hybhub.hybhubaddon.model.MyProcessModel;
public class FirstStepAction extends AbstractSimpleDecisionAction<MyProcessModel>
{
@Override
public Transition executeAction(final MyProcessModel myProcess) throws
֒→
RetryLaterException, Exception
{
if (myProcess.isFail())
{
return Transition.NOK;
}
return Transition.OK;
}
}
Second step, will return success or error based on the error flag
package com.hybhub.hybhubaddon.actions.myprocess;
import de.hybris.platform.processengine.action.AbstractSimpleDecisionAction;
import de.hybris.platform.task.RetryLaterException;
import com.hybhub.hybhubaddon.model.MyProcessModel;
public class SecondStepAction extends AbstractSimpleDecisionAction<MyProcessModel>
{
@Override
public Transition executeAction(final MyProcessModel myProcess) throws
֒→
RetryLaterException, Exception
{
if (myProcess.isError())
{
return Transition.NOK;
}
return Transition.OK;
}
}
Abort step will log something and return OK
6.1. BUSINESS PROCESS
package com.hybhub.hybhubaddon.actions.myprocess;
import de.hybris.platform.processengine.action.AbstractSimpleDecisionAction;
import de.hybris.platform.task.RetryLaterException;
import org.apache.log4j.Logger;
import com.hybhub.hybhubaddon.model.MyProcessModel;
public class AbortStepAction extends AbstractSimpleDecisionAction<MyProcessModel>
{
private final static Logger LOG = Logger.getLogger(AbortStepAction.class);
֒→
@Override
public Transition executeAction(final MyProcessModel myProcess) throws
RetryLaterException, Exception
{
LOG.error("The process " + myProcess.getCode() + " failed !");
return Transition.OK;
}
}
Now we need to wire them all using Spring xml configuration:
<bean id="myProcess"
֒→
class="de.hybris.platform.processengine.definition.ProcessDefinitionResource" >
<property name="resource"
֒→
value="classpath:/hybhubaddon/process/myprocess-process.xml"/>
</bean>
<bean id="firstStepAction" class="com.hybhub.hybhubaddon.actions.myprocess.FirstStepAction"
֒→
parent="abstractAction" />
<bean id="secondStepAction"
֒→
class="com.hybhub.hybhubaddon.actions.myprocess.SecondStepAction"
֒→
parent="abstractAction" />
<bean id="abortStepAction" class="com.hybhub.hybhubaddon.actions.myprocess.AbortStepAction"
֒→
parent="abstractAction" />
Let’s test our new business process using a Groovy script:
117
118
CHAPTER 6. ORDER MANAGEMENT
import com.hybhub.hybhubaddon.model.MyProcessModel
import de.hybris.platform.servicelayer.model.ModelService
import de.hybris.platform.processengine.BusinessProcessService
ModelService modelService = spring.getBean("modelService")
BusinessProcessService bpService = spring.getBean("businessProcessService")
MyProcessModel myprocess = bpService.createProcess("myProcess" +
System.currentTimeMillis(), "myProcess")
myprocess.setFail(true)
myprocess.setError(true)
modelService.save(myprocess)
bpService.startProcess(myprocess)
modelService.refresh(myprocess)
println myprocess.state
You can play around with the two flags and check the result in the HMC. You can see the process
state, and the log for each step.
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 checked by a customer agent.
9. Order manual checked, take the decision to follow the fulfillment process after the manual
check or not.
10. Schedule for cleanUp, try to cleanup a fraudulent or failed order.
11. Cancel order.
6.3. SHOPPING CART HANDLING
119
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/yacceleratorfulfilm
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.
(a) The cart service (cartService) will try to load the cart from the session. In our case
the customer has no 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).
(b) 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.
(c) The calculation service (CalculationService) will calculate the total price of the cart.
(a) 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.
(b) During the checkout process the customer will add or select a delivery address, attach
payment info...
(c) When the Customer places the order, the order is created by making a copy of the cart
(order entries as well).
120
CHAPTER 6. ORDER MANAGEMENT
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 map, based on the different validation success or fail the checkout flow
will often 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.acceleratorstorefrontcom
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:
6.4. CHECKOUT FLOW
121
<bean id="REDIRECT_TO_HYBHUB" class="java.lang.String">
<constructor-arg value="redirect:/checkout/multi/hybhub"/>
</bean>
<alias name="defaultHybhubCheckoutGroup" alias="hybhubCheckoutGroup" />
<bean id="defaultHybhubCheckoutGroup"
֒→
class="de.hybris.platform.acceleratorstorefrontcommons.checkout.steps.CheckoutGroup">
<property name="groupId" value="hybhubCheckoutGroup"/>
<property name="checkoutStepMap">
<map merge="true">
<entry key="multi" value-ref="hybhubMultiStepCheckout"/>
<entry key="hybhub" value-ref="hybhubStep"/>
<entry key="delivery-address"
֒→
value-ref="hybhubDeliveryAddressCheckoutStep"/>
<entry key="delivery-method" value-ref="deliveryMethodCheckoutStep"/>
<entry key="pickup-location" value-ref="pickupLocationCheckoutStep"/>
<entry key="payment-method" value-ref="paymentMethodCheckoutStep"/>
<entry key="summary" value-ref="summaryCheckoutStep"/>
</map>
</property>
<property name="validationResultsMap">
<map merge="true">
<entry key="FAILED" value-ref="REDIRECT_TO_CART"/>
<entry key="REDIRECT_TO_DELIVERY_ADDRESS"
֒→
value-ref="REDIRECT_TO_DELIVERY_ADDRESS"/>
<entry key="REDIRECT_TO_PICKUP_LOCATION"
֒→
value-ref="REDIRECT_TO_PICKUP_LOCATION"/>
<entry key="REDIRECT_TO_CART" value-ref="REDIRECT_TO_CART"/>
<entry key="REDIRECT_TO_PAYMENT_METHOD"
֒→
value-ref="REDIRECT_TO_PAYMENT_METHOD"/>
<entry key="REDIRECT_TO_DELIVERY_METHOD"
֒→
value-ref="REDIRECT_TO_DELIVERY_METHOD"/>
</map>
</property>
<property name="checkoutProgressBar">
<map merge="true">
<entry key="1" value-ref="hybhubStep"/>
<entry key="2" value-ref="deliveryAddressCheckoutStep"/>
<entry key="3" value-ref="deliveryMethodCheckoutStep"/>
<entry key="4" value-ref="paymentMethodCheckoutStep"/>
<entry key="5" value-ref="defaultSummaryCheckoutStep"/>
</map>
</property>
</bean>
Out of the box Hybris already has these steps :
• deliveryMethodCheckoutStep
• pickupLocationCheckoutStep
• paymentMethodCheckoutStep
• summaryCheckoutStep
It also has multiStepCheckout and deliveryAddressCheckoutStep; but because we need to update
their transitions, we declare new beans. Here are the 3 steps we need:
122
CHAPTER 6. ORDER MANAGEMENT
<alias name="defaultHybhubStep" alias="hybhubStep" />
<bean id="defaultHybhubStep" parent="checkoutStep">
<property name="checkoutGroup" ref="hybhubCheckoutGroup"/>
<property name="checkoutStepValidator" ref="hybhubValidator"/>
<property name="transitions">
<map merge="true">
<entry key="previous" value-ref="REDIRECT_MULTI_STEP_CHECKOUT"/>
<entry key="current" value-ref="REDIRECT_TO_HYBHUB"/>
<entry key="next" value-ref="REDIRECT_TO_DELIVERY_ADDRESS"/>
</map>
</property>
<property name="progressBarId" value="hybhubStep"/>
</bean>
<alias name="defaultHybhubMultiStepCheckout" alias="hybhubMultiStepCheckout" />
<bean id="defaultHybhubMultiStepCheckout" parent="checkoutStep">
<property name="checkoutGroup" ref="hybhubCheckoutGroup"/>
<property name="checkoutStepValidator"
֒→
ref="defaultResponsiveMultiStepCheckoutValidator"/>
<property name="transitions">
<map>
<entry key="previous" value-ref="REDIRECT_TO_CART"/>
<entry key="current" value-ref="REDIRECT_MULTI_STEP_CHECKOUT"/>
<entry key="next" value-ref="REDIRECT_TO_HYBHUB"/>
</map>
</property>
<property name="progressBarId" value="multi"/>
</bean>
<alias name="defaultHybhubDeliveryAddressCheckoutStep"
֒→
alias="hybhubDeliveryAddressCheckoutStep" />
<bean id="defaultHybhubDeliveryAddressCheckoutStep" parent="checkoutStep">
<property name="checkoutGroup" ref="hybhubCheckoutGroup"/>
<property name="checkoutStepValidator"
֒→
ref="defaultResponsiveDeliveryAddressCheckoutValidator"/>
<property name="transitions">
<map merge="true">
<entry key="previous" value-ref="REDIRECT_TO_HYBHUB"/>
<entry key="current" value-ref="REDIRECT_TO_DELIVERY_ADDRESS"/>
<entry key="next" value-ref="REDIRECT_TO_DELIVERY_METHOD"/>
</map>
</property>
<property name="progressBarId" value="deliveryAddress"/>
</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 lets you validate the step controller on enter and on exit. Here is our implementation for
the hybhub step:
6.4. CHECKOUT FLOW
package com.hybhub.storefront.checkout.steps.validation.impl;
import de.hybris.platform.acceleratorstorefrontcommons.checkout.steps.validation.AbstractChe ⌋
ckoutStepValidator;
֒→
import de.hybris.platform.acceleratorstorefrontcommons.checkout.steps.validation.ValidationR ⌋
esults;
֒→
import de.hybris.platform.commercefacades.order.data.CartData;
import org.apache.log4j.Logger;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
public class DefaultHybhubValidator extends AbstractCheckoutStepValidator
{
final static Logger LOG = Logger.getLogger(DefaultHybhubValidator.class);
֒→
֒→
@Override
public ValidationResults validateOnEnter(final RedirectAttributes redirectAttributes)
{
final CartData cartData = getCheckoutFacade().getCheckoutCart();
LOG.info("Validating on enter with Hybhub Validator cart : " +
cartData.getCode());
return ValidationResults.SUCCESS;
}
@Override
public ValidationResults validateOnExit()
{
final CartData cartData = getCheckoutFacade().getCheckoutCart();
LOG.info("Validating on exit with Hybhub Validator cart : " +
cartData.getCode());
return ValidationResults.SUCCESS;
}
}
We now need to implement a controller to handle our step:
123
124
CHAPTER 6. ORDER MANAGEMENT
package com.hybhub.storefront.controllers.pages.checkout.steps;
import de.hybris.platform.acceleratorstorefrontcommons.annotations.PreValidateCheckoutStep;
import de.hybris.platform.acceleratorstorefrontcommons.annotations.RequireHardLogIn;
import de.hybris.platform.acceleratorstorefrontcommons.checkout.steps.CheckoutStep;
import de.hybris.platform.acceleratorstorefrontcommons.constants.WebConstants;
import de.hybris.platform.acceleratorstorefrontcommons.controllers.pages.checkout.steps.Abst ⌋
ractCheckoutStepController;
֒→
import de.hybris.platform.cms2.exceptions.CMSItemNotFoundException;
import
import
import
import
import
org.springframework.stereotype.Controller;
org.springframework.ui.Model;
org.springframework.web.bind.annotation.RequestMapping;
org.springframework.web.bind.annotation.RequestMethod;
org.springframework.web.servlet.mvc.support.RedirectAttributes;
@Controller
@RequestMapping(value = "/checkout/multi/hybhub")
public class HybhubStepController extends AbstractCheckoutStepController
{
private static final String HYBHUB = "hybhub";
֒→
֒→
@RequestMapping(method = RequestMethod.GET)
@RequireHardLogIn
@Override
@PreValidateCheckoutStep(checkoutStep = HYBHUB)
public String enterStep(final Model model, final RedirectAttributes
redirectAttributes) throws CMSItemNotFoundException
{
this.prepareDataForPage(model);
storeCmsPageInModel(model, getContentPageForLabelOrId(HYBHUB));
setUpMetaDataForContentPage(model, getContentPageForLabelOrId(HYBHUB));
model.addAttribute(WebConstants.BREADCRUMBS_KEY,
getResourceBreadcrumbBuilder().getBreadcrumbs("checkout.mult ⌋
i.deliveryMethod.breadcrumb"));
model.addAttribute("metaRobots", "noindex,nofollow");
setCheckoutStepLinksForModel(model, getCheckoutStep());
return "pages/checkout/multi/hybhubPage";
}
@RequestMapping(value = "/back", method = RequestMethod.GET)
@RequireHardLogIn
@Override
public String back(final RedirectAttributes redirectAttributes)
{
return getCheckoutStep().previousStep();
}
@RequestMapping(value = "/next", method = RequestMethod.GET)
@RequireHardLogIn
@Override
public String next(final RedirectAttributes redirectAttributes)
{
return getCheckoutStep().nextStep();
}
protected CheckoutStep getCheckoutStep()
{
return getCheckoutStep(HYBHUB);
}
}
6.4. CHECKOUT FLOW
125
To handle the view you need to create pages/checkout/multi/hybhubPage.jsp:
<%@
<%@
<%@
<%@
<%@
<%@
<%@
<%@
<%@
page trimDirectiveWhitespaces="true"%>
taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
taglib prefix="template" tagdir="/WEB-INF/tags/responsive/template"%>
taglib prefix="cms" uri="http://hybris.com/tld/cmstags"%>
taglib prefix="spring" uri="http://www.springframework.org/tags"%>
taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
taglib prefix="formElement" tagdir="/WEB-INF/tags/responsive/formElement" %>
taglib prefix="multi-checkout" tagdir="/WEB-INF/tags/responsive/checkout/multi"%>
taglib prefix="ycommerce" uri="http://hybris.com/tld/ycommercetags" %>
<template:page pageTitle="\${pageTitle}" hideHeaderLinks="true">
<div class="row">
<div class="col-sm-6">
<div class="checkout-headline">
<span class="glyphicon glyphicon-lock"></span>
<spring:theme code="checkout.multi.secure.checkout" text="Secure
Checkout"></spring:theme>
֒→
</div>
<multi-checkout:checkoutSteps checkoutSteps="\${checkoutSteps}"
֒→
progressBarId="hybhubStep">
<jsp:body>
<ycommerce:testId code="hybhub">
<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>
</ycommerce:testId>
</jsp:body>
</multi-checkout:checkoutSteps>
</div>
<div class="col-sm-6 hidden-xs">
<h1>This is the Hybhub step</h1>
</div>
</div>
</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:
$contentCatalog=electronicsContentCatalog
$contentCV=catalogVersion(CatalogVersion.catalog(Catalog.id[default=$contentCatalog]),Catalo ⌋
֒→
gVersion.version[default=Staged])[default=$contentCatalog:Staged]
INSERT_UPDATE ContentPage;$contentCV[unique=true];uid[unique=true];name;masterTemplate(uid,$ ⌋
contentCV);label;defaultPage[default=’true’];approvalStatus(code)[default=’approved’];h ⌋
֒→
omepage[default=’false’];
֒→
;;hybhub;Hybhub Page;MultiStepCheckoutSummaryPageTemplate;hybhub
Don’t forget to run a synchronization or to change the catalog to the Online one,
126
CHAPTER 6. ORDER MANAGEMENT
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:
INSERT_UPDATE BaseStore;uid[unique=true];checkoutFlowGroup;
;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 as 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:
<extension name="assistedservicefacades"/>
<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 :
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 : <a>http://localhost:9001/hybhubstorefront/?site=electronics&asm=true</a>.
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;
6.6. CS COCPKIT
127
• 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 : <a>http://localhost:9001/cscockpit/</a>. It is meant to be used by operators in
a call center environment for customers, pre-sales and post sales operations.
We recall that from the customer service cockpit, operators can do the following :
• Manage customers (create or edit);
• Manage orders on 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
128
CHAPTER 6. ORDER MANAGEMENT
Figure 6.1: Order business Process
129
6.6. CS COCPKIT
Figure 6.2: Order Model Classes
Figure 6.3: Electronic ASM
130
CHAPTER 6. ORDER MANAGEMENT
Chapter 7
Search and navigation
131
132
CHAPTER 7. SEARCH AND NAVIGATION
SAP Hybris provides fast and customizable search and navigation with the help of an Apache
SOLR server ([More information](http://lucene.apache.org/solr/)).
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 defines 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 considers a connection attempt a failure
– Socket timeout, timeout before SAP Hybris considers a socket access a failure
– Total connections, total open connections 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.
– 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 massive impact on the performance
– 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 newly
created one
– 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
7.2. SOLR INDEXED PROPERTY
133
– Error 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
– A list of indexed queries
– 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 needs 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.
134
CHAPTER 7. SEARCH AND NAVIGATION
Example, with the following customized product model :
<itemtype code="Product" autocreate="false" generate="false">
<attributes>
<attribute qualifier="exportToGoogleShopping" type="java.lang.Boolean">
<persistence type="property" />
</attribute>
<attribute qualifier="lastCustomerReview" type="java.lang.String">
<persistence type="property" />
</attribute>
</attributes>
</itemtype>
We will create 2 new properties for our product index: one facet property from the exportToGoogleShopping and the other free text search property from lastCustomerReview:
exportToGoogleShopping facet :
INSERT_UPDATE SolrIndexedProperty;solrIndexedType(identifier)[unique=true];name[unique=true] ⌋
;type(code);sortableType(code);currency[default=false];localized[default=false];multiVa ⌋
֒→
lue[default=false];facet[default=true];facetType(code);facetSort(code);priority;visible ⌋
֒→
;useForSpellchecking[default=false];useForAutocomplete[default=false];fieldValueProvide ⌋
֒→
r;valueProviderParameter;facetDisplayNameProvider;customFacetSortProvider;topValuesProv ⌋
֒→
ider;rangeSets(name)
֒→
;electronicsProductType;exportToGoogleShopping;boolean;;;;false;;MultiSelectAnd;;100;true;;; ⌋
֒→
springELValueProvider;getExportToGoogleShopping();;
lastCustomerReview free text search :
INSERT_UPDATE SolrIndexedProperty;solrIndexedType(identifier)[unique=true];name[unique=true] ⌋
;type(code);sortableType(code);currency[default=false];localized[default=false];multiVa ⌋
֒→
lue[default=false];facet[default=false];facetType(code);facetSort(code);priority;visibl ⌋
֒→
e;useForSpellchecking[default=false];useForAutocomplete[default=false];fieldValueProvid ⌋
֒→
er;valueProviderParameter;ftsQuery;ftsQueryBoost;ftsQueryMinTermLength;ftsWildcardQuery ⌋
֒→
֒→
;ftsWildcardQueryBoost;ftsWildcardQueryMinTermLength;includeInResponse
;electronicsProductType;lastCustomerReview;string;;;;;;;;100;true;;;springELValueProvider;ge ⌋
֒→
tLastCustomerReview();true;500;5;true;100;10;false
In order to add a new free text attribute you need to configure the solr search configuration with
legacy mode to false, or to update the commerceSearchTextPopulator bean and add your new field,
in our case lastCustomerReview :
7.2. SOLR INDEXED PROPERTY
135
INSERT_UPDATE SolrSearchConfig;description[unique=true];pageSize;legacyMode
;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 resolver
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<T extends ItemModel, MDATA, QDATA>, the only abstract method that you have to implement is addFieldValues, here is an example of a simple value provider for our exportToGoogleShopping attribute :
package com.hybhub.hybhubaddon.search.solrfacetsearch.provider.impl;
import
import
import
import
import
import
de.hybris.platform.core.model.product.ProductModel;
de.hybris.platform.solrfacetsearch.config.IndexedProperty;
de.hybris.platform.solrfacetsearch.config.exceptions.FieldValueProviderException;
de.hybris.platform.solrfacetsearch.indexer.IndexerBatchContext;
de.hybris.platform.solrfacetsearch.indexer.spi.InputDocument;
de.hybris.platform.solrfacetsearch.provider.impl.AbstractValueResolver;
public class ProductExportToGS extends AbstractValueResolver<ProductModel, Object, Object>
{
֒→
֒→
֒→
֒→
@Override
protected void addFieldValues(final InputDocument inputDocument, final
IndexerBatchContext IndexerBatchContext,
final IndexedProperty indexedProperty, final ProductModel
productModel,
final ValueResolverContext<Object, Object> valueResolverContext)
throws FieldValueProviderException
{
inputDocument.addField(indexedProperty,
productModel.getExportToGoogleShopping() == null ?
Boolean.FALSE : productModel.getExportToGoogleShopping(),
valueResolverContext.getFieldQualifier());
}
}
We need to create a Spring bean for our value provider; it must have abstractValueResolver as
a parent bean definition:
136
CHAPTER 7. SEARCH AND NAVIGATION
<bean id="productExportToGS"
֒→
class="com.hybhub.hybhubaddon.search.solrfacetsearch.provider.impl.ProductExportToGS"
parent="abstractValueResolver"/>
Build your platform and run the following impex query:
INSERT_UPDATE SolrIndexedProperty;solrIndexedType(identifier)[unique=true];name[unique=true] ⌋
;type(code);sortableType(code);currency[default=false];localized[default=false];multiVa ⌋
֒→
lue[default=false];facet[default=true];facetType(code);facetSort(code);priority;visible ⌋
֒→
;useForSpellchecking[default=false];useForAutocomplete[default=false];fieldValueProvide ⌋
֒→
r;valueProviderParameter;facetDisplayNameProvider;customFacetSortProvider;topValuesProv ⌋
֒→
ider;rangeSets(name)
֒→
;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 :
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, 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.
7.3. INDEXING LISTENERS
137
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} >=
}}
UNION
{{
SELECT {p:PK} AS
֒→
?lastIndexTime)
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, 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 one job.
INSERT_UPDATE SolrExtIndexerCronJob;code[unique=true];job(code)[unique=true];sessionLa ⌋
nguage(isocode);sessionCurrency(isoCode);indexedType(identifier)[unique=true];que ⌋
֒→
ry;facetSearchConfig(name);indexerOperation(code);sessionUser(uid);queryParameter ⌋
֒→
Provider;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. Here you can list the
attribute you want to update. This is where you configure the partial behavior,
if you don’t configure any properties all attributes are updated
• Delete query this deletes documents from the index. For example you can select all products
that are not authorized or have been discontinued.
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;
138
CHAPTER 7. SEARCH AND NAVIGATION
• 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 :
package com.hybhub.hybhubaddon.search.solrfacetsearch.indexer.impl;
import org.springframework.beans.factory.annotation.Required;
public abstract class AbstractHybhubListener
{
private String name;
public String getName()
{
return name;
}
@Required
public void setName(final String name)
{
this.name = name;
}
}
Example how to implement an IndexerListener listener :
7.3. INDEXING LISTENERS
139
package com.hybhub.hybhubaddon.search.solrfacetsearch.indexer.impl;
import de.hybris.platform.solrfacetsearch.indexer.IndexerContext;
import de.hybris.platform.solrfacetsearch.indexer.IndexerListener;
import de.hybris.platform.solrfacetsearch.indexer.exceptions.IndexerException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HybhubIndexerListenerImpl extends AbstractHybhubListener implements
֒→
IndexerListener
{
private final Logger LOG = LoggerFactory.getLogger(HybhubIndexerListenerImpl.class);
@Override
public void beforeIndex(final IndexerContext arg0) throws IndexerException
{
LOG.info("Before Index : " + getName());
}
@Override
public void afterIndex(final IndexerContext arg0) throws IndexerException
{
LOG.info("After Index : " + getName());
}
@Override
public void afterIndexError(final IndexerContext arg0) throws IndexerException
{
LOG.info("After Index Error : " + getName());
}
}
Example how to declare a bean for the listener and configure it as global :
֒→
<bean id="globaltHybhubIndexerListener" class="com.hybhub.hybhubaddon.search.solrfac ⌋
etsearch.indexer.impl.HybhubIndexerListenerImpl">
<property name="name" value="globaltHybhubIndexerListener" />
</bean>
<bean id="globaltHybhubIndexerListenerDefinition" parent="solrListenerDefinition">
<property name="listener" ref="globaltHybhubIndexerListener" />
</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)
140
CHAPTER 7. SEARCH AND NAVIGATION
• 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...
To see this with a real world example, you can go to any of the big online retailers. Here, you will
notice that when searching for a product by entering its name, you 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:
INSERT_UPDATE SolrIndexedProperty;solrIndexedType(identifier)[unique=true];name[unique=true] ⌋
;type(code);fieldValueProvider;facet;facetType(code);priority;
֒→
;electronicsProductType;pickupAvailableFlag;boolean;productPickupAvailabilityValueProvider;t ⌋
rue;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 it 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"; the following is an example.
7.6. AUTO SUGGESTION
141
# Define price range set
INSERT_UPDATE
֒→
SolrValueRangeSet;name[unique=true];qualifier;type;solrValueRanges(\&rangeValueRefID)
;electronicsPriceRangeUSD;USD;double;rangeRefUSD1,rangeRefUSD2,rangeRefUSD3,rangeRefUSD4,ran ⌋
geRefUSD5
֒→
# Define price ranges
INSERT_UPDATE SolrValueRange;\&rangeValueRefID;solrValueRangeSet(name)[unique=true];name[uni ⌋
֒→
que=true];from;to
;rangeRefUSD1;electronicsPriceRangeUSD;
$0-$49.99;
0; 49.99
;rangeRefUSD2;electronicsPriceRangeUSD;
$50-$199.99; 50; 199.99
;rangeRefUSD3;electronicsPriceRangeUSD;
$200-$499.99; 200; 499.99
;rangeRefUSD4;electronicsPriceRangeUSD;
$500-$999.99; 500; 999.99
;rangeRefUSD5;electronicsPriceRangeUSD;$1,000-$100,000;1000; 100000
When you create a SolrIndexedProperty you can specify rangeSets.
Auto suggestion
If a SOLR indexed property is configured to be auto complete, its content becomes available for a
search from the Search Box Component.
To activate it from an indexed property, execute the following impex query :
INSERT_UPDATE SolrIndexedProperty;solrIndexedType(identifier)[unique=true];name[unique=true] ⌋
;useForAutocomplete
֒→
;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 configuration. They provide you with the
ability to redirect the customer to a page for a given query. For example, if a customer enters the
word cart under the search component, you can redirect him or her to the cart page.
First you need a SolrFacetSearchKeywordRedirect. This holds the following:
142
CHAPTER 7. SEARCH AND NAVIGATION
• 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 one of the following:
– a category redirect;
– a direct url;
– a page redirect;
– a product redirect.
Below is an example of how to create a new redirect for a product:
$productCatalog=electronicsProductCatalog
$productCatalogVersion=catalogVersion(CatalogVersion.catalog(Catalog.id[default=$productCata ⌋
֒→
log]),CatalogVersion.version[default=Staged])[default=$productCatalog:Staged]
INSERT_UPDATE SolrProductRedirect;redirectItem(code,$productCatalogVersion)[unique=true];\&r ⌋
֒→
edirectRefID
;726510;contentCatalogName-redirectRefID-726510
INSERT_UPDATE SolrFacetSearchKeywordRedirect;facetSearchConfig(name)[unique=true];language(i ⌋
socode)[unique=true];keyword[unique=true];matchType(code)[unique=true];redirect(&redire ⌋
֒→
֒→
ctRefID);ignoreCase
;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, 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 configuration folder config/solr/instances/default/ configsets/default/conf/lang/stopwords_en.txt
(the example illustrates stopwords for English, but other languages are available).
To manage stopwords from SAP Hybris, one first creates them from Impex queries:
INSERT_UPDATE SolrStopWord;facetSearchConfig(name)[unique=true];language(isocode)[unique=tru ⌋
֒→
e];stopword[unique=true]
;electronicsIndex;en;the
7.9. SYNONYMS
143
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. Let us 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 synonym:
INSERT_UPDATE SolrSynonymConfig;facetSearchConfig(name)[unique=true];language(isocode)[uniqu ⌋
e=true];synonymFrom[unique=true];synonymTo
֒→
;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 is the Impex query:
$productCatalog=electronicsProductCatalog
$productCatalogVersion=catalogVersion(CatalogVersion.catalog(Catalog.id[default=$productCata ⌋
֒→
log]),CatalogVersion.version[default=Online])[default=$productCatalog:Online]
INSERT_UPDATE SolrHeroProductDefinition;$productCatalogVersion[unique=true];category(code,
֒→
$productCatalogVersion);code[unique=true];indexedType(identifier);products(code,
֒→
$productCatalogVersion)
;;575;575_electronicsProductType;electronicsProductType;478828
INSERT_UPDATE Product;code[unique=true];$productCatalogVersion[unique=true];solrHeroProductD ⌋
efinitions(code)
֒→
;478828;;575_electronicsProductType
Now navigate to home -> open catalog -> cameras -> digital cameras. You should see your product
on top of the search result.
Boost rules
Boost rules help you adjust the SOLR server answers in the way that for example product in stock
shows up before out of stock products. Based on different factors, you will artificially boost the
144
CHAPTER 7. SEARCH AND NAVIGATION
results.
SAP Hybris implemented boosting at query time, meaning that you do not need to
re-index to see the changes!
For example, for the product 1312564 to always be on top, you can execute this Impex query
below:
$solrIndexedType=electronicsProductType
INSERT_UPDATE GlobalSolrSearchProfile;code[unique=true];indexedType(identifier)
;globalcatalog-srch-profile0000000001;$solrIndexedType
INSERT_UPDATE SolrBoostRule;propertyValue[unique=true];solrIndexedProperty(name);operator(co ⌋
de)[unique=true];boostFactor;solrSearchProfiles(code)
֒→
;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 the SOLR query
executed when you search for battery :
Now if you type "battery"" into your search box component, you may 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 to their boost rules. Below
SOLR query is executed when you search for battery:
7.10. HERO PRODUCTS & BOOST RULES
145
localhost:8983/solr/master_electronics_Product/select?
q=....’((code_string:battery^90.0)+
OR+(keywords_text_en:battery^20.0)+
OR+(manufacturerName_text:battery^40.0)+
OR+(categoryName_text_en_mv:battery^20.0)+
OR+(lastCustomerReview_string:battery^100.0)+
OR+(ean_string:battery^100.0)+
OR+(name_text_en:battery^50.0))+
OR+((keywords_text_en:battery~^10.0)+
OR+(manufacturerName_text:battery~^20.0)+
OR+(categoryName_text_en_mv:battery~^10.0)+
OR+(lastCustomerReview_string:battery~^50.0)+
OR+(name_text_en:battery~^25.0))+
OR+((code_string:battery*^45.0)+
OR+(ean_string:battery*^50.0))+
OR+((keywords_text_en:"battery"^40.0)+
OR+(manufacturerName_text:"battery"^80.0)+
OR+(categoryName_text_en_mv:"battery"^40.0)+
OR+(name_text_en:"battery"^100.0))’})+
//
// This is our custom boost query !
//
AND+({!func+v="sum(map(query({!v=code_string:1312564}),0,0,0,1000.0))"})
//
&sort=score+desc,inStockFlag_boolean+desc,score+desc
&start=0&rows=20
&facet.field=Resolution,+80_string
&facet.field=Mounting,+1867_en_string
&facet.field=categoryPath_string_mv
&facet.field=Megapixel,+63_string
&facet.field=exportToGoogleShopping_boolean
&facet.field=availableInStores_string_mv
&facet.field=pickupAvailableFlag_boolean
&facet.field=Colour+of+product,+1766_en_string
&facet.field=price_usd_string
&facet.field=allPromotions_string_mv
&facet.field=allCategories_string_mv
&facet.field=Lens+type,+472_en_string_mv
&facet.field=category_string_mv
&facet.field=brand_string_mv
&facet=true
&facet.sort=count
&facet.mincount=1
&facet.limit=50
&spellcheck=true
&spellcheck.q=battery
&spellcheck.dictionary=en
&spellcheck.collate=true
&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 :
146
CHAPTER 7. SEARCH AND NAVIGATION
log4j2.logger.search.name=de.hybris.platform.solrfacetsearch
log4j2.logger.search.level = debug
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 does not "think"" that this needs 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 by far.
How to change boostRuleValidator bean using AOP, first you need to create a class to handle the
change. This is called around the validate method call from the interceptor:
package com.hybhub.hybhubaddon.commercesearch.searchandizing.boost.interceptors;
import
֒→
de.hybris.platform.commercesearch.searchandizing.boost.interceptors.BoostRuleValidator;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.beans.factory.annotation.Required;
public class HybhubBoostRuleValidatorAspect
{
private int maxBoostFactorValue;
public void around(final ProceedingJoinPoint joinPoint) throws Throwable
{
final BoostRuleValidator boostRuleValidator = (BoostRuleValidator)
֒→
joinPoint.getTarget();
boostRuleValidator.setMaxBoostFactorValue(maxBoostFactorValue);
joinPoint.proceed();
}
@Required
public void setMaxBoostFactorValue(final int maxBoostFactorValue)
{
this.maxBoostFactorValue = maxBoostFactorValue;
}
}
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:
7.10. HERO PRODUCTS & BOOST RULES
147
<bean id="hybhubBoostRuleValidatorMethodInterceptor"
class="com.hybhub.hybhubaddon.commercesearch.searchandizing.boost.interceptors.Hybhu ⌋
֒→
bBoostRuleValidatorAspect">
<property name="maxBoostFactorValue" value="500" />
</bean>
<aop:config>
<aop:aspect id="boostValidatorAspect"
֒→
ref="hybhubBoostRuleValidatorMethodInterceptor">
<aop:pointcut id="boostValidatorPoincut"
expression="execution(* de.hybris.platform.commercesearch.searchandi ⌋
zing.boost.interceptors.BoostRuleValidator.onValidate(..))"
֒→
/>
֒→
<aop:around method="around" pointcut-ref="boostValidatorPoincut"/>
</aop:aspect>
</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:
INSERT_UPDATE SolrBoostRule;propertyValue[unique=true];solrIndexedProperty(name);operator(co ⌋
֒→
de)[unique=true];boostFactor;solrSearchProfiles(code)
;1312564;code;EQUAL_TO;500;globalcatalog-srch-profile0000000001
148
CHAPTER 7. SEARCH AND NAVIGATION
Chapter 8
Platform basics
149
150
CHAPTER 8. 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.
• 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
151
8.2. UPDATE
Update
During the update process SAP Hybris updates 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.
• doesn’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:
MariaDB [hybris]> select * from SYSTEMINIT;
id
locked tenantId clusterNode lockdate
process
globalID
1
master
0
20...
System update
locked = 1 means you cannot start an update or an initialization.
instanceId
...
152
CHAPTER 8. PLATFORM BASICS
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 is an example using AbstractSystemSetup from commerceservices as a starting point:
8.4. UPDATE AND INITIALIZATION HOOKS
package com.hybhub.setup;
import
import
import
import
import
import
import
de.hybris.platform.commerceservices.setup.AbstractSystemSetup;
de.hybris.platform.core.initialization.SystemSetup;
de.hybris.platform.core.initialization.SystemSetup.Process;
de.hybris.platform.core.initialization.SystemSetup.Type;
de.hybris.platform.core.initialization.SystemSetupContext;
de.hybris.platform.core.initialization.SystemSetupParameter;
de.hybris.platform.core.initialization.SystemSetupParameterMethod;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.hybhub.constants.HybhubhookConstants;
@SystemSetup(extension = HybhubhookConstants.EXTENSIONNAME)
public class HybhubHookSystemSetup extends AbstractSystemSetup
{
final static Logger LOG = LoggerFactory.getLogger(HybhubHookSystemSetup.class);
@SystemSetupParameterMethod
@Override
public List<SystemSetupParameter> getInitializationOptions()
{
final List<SystemSetupParameter> params = new ArrayList<>();
params.add(createBooleanSystemSetupParameter("key", "Import ?", false));
return params;
}
֒→
֒→
֒→
֒→
}
@SystemSetup(type = Type.ESSENTIAL, process = Process.ALL)
public void createEssentialData(final SystemSetupContext context)
{
final boolean doImport = getBooleanSystemSetupParameter(context, "key");
if (doImport)
{
logInfo(context, "Starting importing essential data for " +
HybhubhookConstants.EXTENSIONNAME);
importImpexFile(context, "/hybhubcore/essential.impex");
synchCatalogs();
}
else
{
logError(context, "Did not import essential data !", null);
}
}
@SystemSetup(type = Type.PROJECT, process = Process.ALL)
public void createProjectData(final SystemSetupContext context)
{
final boolean doImport = getBooleanSystemSetupParameter(context, "key");
if (doImport)
{
logInfo(context, "Starting importing project data for " +
HybhubhookConstants.EXTENSIONNAME);
importImpexFile(context, "/hybhubcore/project.impex");
synchCatalogs();
}
else
{
logError(context, "Did not import project data !", null);
}
}
private void synchCatalogs()
{
getSetupSyncJobService().createContentCatalogSyncJob("electronicsContentCata ⌋
log");
getSetupSyncJobService().createProductCatalogSyncJob("electronicsProductCata ⌋
log");
}
153
154
CHAPTER 8. PLATFORM BASICS
You need to declare the system setup class as a bean:
<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 <extension_name>/resources/impex folder. In particular:
• For essential data: The platform scans the <extension_name>/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 <extension_name>/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 <extension_name>.essentialdata-impex-pattern.
• For project data, use <extension_name>.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 <extension_name>.essentialdata-impexpattern=impex.
In contrast to the example above, the pattern <extension_name>.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 <extension_name>.essentialdata-impex-pattern=impex/essentialdataimpex
8.6. SESSIONS HANDLING
155
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:
"#% impex.includeExternalData(SampleDataManager.class.getResourceAsStream(""/firstFileToBeIm ⌋
֒→
ported.csv""), ""utf-8"", 0, 0
֒→
);";
"#% impex.includeExternalData(SampleDataManager.class.getResourceAsStream(""/secondFileToBeI ⌋
mported.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):
def sessionService = spring.getBean("sessionService")
def jaloSession = sessionService.getCurrentSession().getJaloSession()
def sessionContext = jaloSession.getSessionContext()
println jaloSession.getHttpSessionId()
println sessionContext.getLanguage()
println sessionContext.getLocale()
156
CHAPTER 8. PLATFORM BASICS
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.
<meta key="backoffice-module" value="true"/>
<meta key="extgen-template-extension" value="true"/>
<meta key="modulegen-name" value="accelerator,b2baccelerator,chinaaccelerator"/>
8.7. EXTENSIONS STRUCTURES
157
localextensions.xml
SAP Hybris consists of a number of extensions. You can 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.
For examples :
<extension dir="${HYBRIS_BIN_DIR}/custom/hybhubaddon"/>
<path dir=’${HYBRIS_BIN_DIR}/custom’ autoload=’false’ />
<extension name="hybhubaddon"/>
<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 :
<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):
...
[echo]
[echo]
[echo]
[echo]
[echo]
[echo]
[echo]
[echo]
[echo]
....
------- Extensions in dependency order ( options:
--- @deprecated: is deprecated, p: platform extension,*: auto-required
--- ?: lazy-loaded, i: got items.xml, b: got beans.xml, c: got core module
--- w: got web module, h: got HMC module )
----core 6.0.0.0-SNAPSHOT [p*cib]
testweb 6.0.0.0-SNAPSHOT [p*w]
scripting 6.0.0.0-SNAPSHOT [p*ci]
158
CHAPTER 8. PLATFORM BASICS
Create a new extension
You can create new extensions based on an existing template. The example below creates a new
extension based on the yempty template:
$ platform ant extgen
...
...
[input]
[input] Please choose a template for generation.
[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)
yempty
[input]
[input] Please choose the name of your extension. It has to start with a letter followed
֒→
by letters and/or numbers.
[input] Press [Enter] to use the default value [training]
myextension
[input]
[input] Please choose the package name of your extension. It has to fulfill java package
֒→
name convention.
[input] Press [Enter] to use the default value [org.training]
com.hybhub
...
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”:
8.8. CONFIGURATION
159
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<extensioninfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
֒→
xsi:noNamespaceSchemaLocation="extensioninfo.xsd">
<extension abstractclassprefix="Generated" classprefix="Hybhubhook"
֒→
managername="HybhubhookManager"
managersuperclass="de.hybris.platform.jalo.extension.Extension"
֒→
name="hybhubhook" usemaven="true">
<requires-extension name="commerceservices" />
<coremodule generated="true" manager="com.hybhub.jalo.HybhubhookManager"
֒→
packageroot="com.hybhub" />
<webmodule jspcompile="false" webroot="/hybhubhook" />
</extension>
</extensioninfo>
Then you can manage your dependencies inside external-dependencies.xml:
<project xmlns="http://maven.apache.org/POM/4.0.0"
֒→
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
֒→
<modelVersion>4.0.0</modelVersion>
<groupId>de.hybris.platform</groupId>
<artifactId>hybhubhook</artifactId>
<version>5.0.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.1</version>
</dependency>
</dependencies>
</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:
160
CHAPTER 8. PLATFORM BASICS
• config/local.properties
• your extensions project.properties files
• platform directory project.properties file
Configuration properties are defined using a key and a value; for example:
#A comment
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
An example of how to get a configuration key from your code is below:
def configurationService = spring.getBean("configurationService")
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.Config
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 <CHANGE_ME>
keyword. For example within my configuration, I have :
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):
8.9. BUILD
161
export y_hybhub_config=fromConsole
Then from the HAC:
def configurationService = spring.getBean("configurationService")
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;
162
CHAPTER 8. PLATFORM BASICS
• 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 built:
<macrodef name="hybhubhook_before_build">
<sequential>
<echo message="Hybhub is being build !!" level="info"/>
</sequential>
</macrodef>
Tenant
SAP Hybris can run in a multi tenant mode, which means each tenant is 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.
8.11. CACHE
163
To declare new tenants:
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:
allowed.extensions=core;promotions
forbidden.extensions=b2bapprovalprocess;hybhubaddon
Cache
SAP Hybris cache helps 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 be used. When you call
a getter on an item attribute, if it hasn’t been loaded yet, it will be then 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 regions. Each region has its own configuration, caches different
kind of objects, and has a maximum size. Regions can have different kinds of eviction strategy:
164
CHAPTER 8. PLATFORM BASICS
• 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 we configure for our extension named hybhubhook a new global spring context file:
hybhubhook.global-context=hybhubhook-cache-spring.xml
Then we create a new file under the resources folder hybhubhook-cache-spring.xml:
<?xml version="1.0" encoding="UTF-8"?>
<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"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd"
default-lazy-init="true">
<bean id="productCacheRegionRegistrar"
֒→
class="de.hybris.platform.regioncache.region.CacheRegionRegistrar"
c:region-ref="productCacheRegion" />
֒→
<alias name="defaultProductCacheRegion" alias="productCacheRegion" />
<bean name="defaultProductCacheRegion"
֒→
class="de.hybris.platform.regioncache.region.impl.EHCacheRegion" lazy-init="false">
<constructor-arg name="name" value="productCacheRegion" />
<constructor-arg name="maxEntries" value="1" />
<constructor-arg name="evictionPolicy" value="LFU" />
<constructor-arg name="statsEnabled" value="true" />
<constructor-arg name="exclusiveComputation" value="true" />
<property name="handledTypes">
<array>
<value>1</value>
</array>
</property>
</bean>
</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.
8.12. INTERCEPTORS
165
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.
An example of how to create an interceptor for product items follows.
166
CHAPTER 8. PLATFORM BASICS
package com.hybhub.hybhubaddon.servicelayer.interceptor;
import
import
import
import
de.hybris.platform.core.model.product.ProductModel;
de.hybris.platform.servicelayer.interceptor.InterceptorContext;
de.hybris.platform.servicelayer.interceptor.InterceptorException;
de.hybris.platform.servicelayer.interceptor.RemoveInterceptor;
import java.util.regex.Pattern;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ProductRemoveInterceptor implements RemoveInterceptor<ProductModel>
{
֒→
final private static Logger LOG =
LoggerFactory.getLogger(ProductRemoveInterceptor.class);
final private static Pattern PROTECTED_PRODUCTS = Pattern.compile("^[0-9]+$");
֒→
֒→
@Override
public void onRemove(final ProductModel prd, final InterceptorContext ctx) throws
InterceptorException
{
LOG.info("Removing product : " + prd.getCode());
if (PROTECTED_PRODUCTS.matcher(prd.getCode()).find())
{
throw new InterceptorException("Product is protected, cannot remove
it !");
}
LOG.info("Product : " + prd.getCode() + " removed");
}
}
You need to declare the interceptor as a Spring bean and to configure the type mapping :
<alias name="defaultProductRemoveInterceptor" alias="productRemoveInterceptor" />
<bean id="defaultProductRemoveInterceptor"
֒→
class="com.hybhub.hybhubaddon.servicelayer.interceptor.ProductRemoveInterceptor" />
<bean id="productRemoveInterceptorMapping"
֒→
class="de.hybris.platform.servicelayer.interceptor.impl.InterceptorMapping">
<property name="interceptor" ref="productRemoveInterceptor" />
<property name="typeCode" value="Product" />
</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;
8.13. TRANSACTIONS
167
• 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 :
final Map<String, Object> params =
֒→
ImmutableMap.of(InterceptorExecutionPolicy.DISABLED_INTERCEPTOR_TYPES,
ImmutableSet.of(InterceptorExecutionPolicy.DisabledType.VALIDATE));
sessionService.executeInLocalViewWithParams(params, new SessionExecutionBody()
{
@Override
public void executeWithoutResult()
{
modelService.save(item);
// executed without any validate interceptors
}
});
Transactions
Transactions are used to keep the data consistent at any time. SAP Hybris provides a wrapper to
easily work with transactions.
A simple groovy example follows below.
def transaction = de.hybris.platform.tx.Transaction.current()
transaction.begin()
//commit all changes
transaction.commit()
//rollback all changes
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 advantage
of TransactionBody is that you don’t need to manually handle the transactions over and over:
168
CHAPTER 8. PLATFORM BASICS
Transaction.current().execute( new TransactionBody()
{
public <Object> Object execute()
{
//Everything here is contained within a single transaction
return something;
}
}
);
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. Tasks are scheduled actions like cronjob a simplified version;
they have 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).
Each task can be executed on any cluster node. The first cluster to fetch and lock the task
would run it. If you need to deactivate the task engine on a given node, you can do it from the
configuration file:
task.engine.loadonstartup=false
A task can be scheduled based on:
• time, holds its execution time;
• event, holds at least one task condition item to specify when to trigger the task.
Chapter 9
Platform core
169
170
CHAPTER 9. 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:
package com.hybhub.event;
import de.hybris.platform.servicelayer.event.events.AbstractEvent;
public class HybhubEvent extends AbstractEvent
{
private final String name;
public HybhubEvent(final String name)
{
this.name = name;
}
@Override
public String toString()
{
return "Hybhub Event : " + this.name;
}
}
Then to create a listener you extend de.hybris.platform.servicelayer.event.impl.AbstractEventListener
:
9.1. EVENTS
171
package com.hybhub.event;
import de.hybris.platform.servicelayer.event.impl.AbstractEventListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HybhubListener extends AbstractEventListener<HybhubEvent>
{
private static final Logger LOG = LoggerFactory.getLogger(HybhubListener.class);
@Override
protected void onEvent(final HybhubEvent hybhubEvent)
{
LOG.info("Received event(Hybhub Event) : " + hybhubEvent);
}
}
Finally you need to create a Spring bean for your listener :
<bean id="hybhubListener" class="com.hybhub.event.HybhubListener"
parent="abstractEventListener" />
To try your event run this Groovy script:
import com.hybhub.event.HybhubEvent
def eventService = spring.getBean("eventService")
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.
172
CHAPTER 9. PLATFORM CORE
package com.hybhub.event;
import de.hybris.platform.servicelayer.event.ClusterAwareEvent;
import de.hybris.platform.servicelayer.event.events.AbstractEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HybhubEvent extends AbstractEvent implements ClusterAwareEvent
{
private static Logger LOG = LoggerFactory.getLogger(HybhubEvent.class);
private final String name;
public HybhubEvent(final String name)
{
LOG.info(Thread.currentThread().getName());
this.name = name;
}
@Override
public String toString()
{
LOG.info(Thread.currentThread().getName());
return "Hybhub Event : " + this.name;
}
@Override
public boolean publish(final int sourceClusterId, final int targetClusterId)
{
return true; //Returning true means your event will be broadcast on all nodes
}
}
• update the Spring bean platformClusterEventSender with an executor:
<bean id="platformClusterEventSender"
֒→
class="de.hybris.platform.servicelayer.event.impl.PlatformClusterEventSender">
<property name="serializationService" ref="serializationService"/>
<property name="tenant" ref="tenantFactory"/>
<property name="executor">
<bean class="java.util.concurrent.Executors"
֒→
factory-method="newCachedThreadPool"/>
</property>
</bean>
9.2. IMPEX
173
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. That means *import and export*, which is an out-of-the-box CSV-based import
framework. From an impex file you can do the following:
• 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.
174
CHAPTER 9. PLATFORM CORE
– 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.EClassSuperCategoryDe
– 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]).
9.2. IMPEX
175
Impex header syntax is case sensitive
An example with Title item type follows below:
INSERT Title;code;name[lang=en]
UPDATE Title;code[unique=true];name[lang=en]
INSERT_UPDATE Title;code[unique=true];name[lang=en]
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 :
INSERT User;uid[unique=true]
Customer;aCustomer
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). 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 look
them up based on their own attributes. Add a comment to this line
INSERT Product;code;unit(code);catalogVersion(catalog(id), version)
;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:
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 is completely ignored during import:
176
CHAPTER 9. PLATFORM CORE
INSERT_UPDATE Product;code
#Begin importing products
;product1;
#Finished importing products
Macro
Impex files can easily get large; 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:
#Macro definition
$unit=pieces
$variantType=LaptopVariant
$aid=MBP$manufacturer=Apple
$catalogVersion=catalogversion(catalog(id[default=$productCatalog]),version[default=’Staged’ ⌋
֒→
])[unique=true,default=$productCatalog:Staged]
$supercategories=supercategories(code, $catalogVersion)
INSERT_UPDATE Product;code[unique=true];$supercategories;manufacturerName;manufacturerAID;un ⌋
it(code);variantType(code);$catalogVersion;$approved
֒→
;000010;000100;$manufacturer;$aid13;$unit;$variantType
;000011;000100;$manufacturer;$aid15;$unit;$variantType
Abbreviations
Another way to shorten Impex files is to use abbreviations. You may use system wide regex
replacement for you Impex headers. For example, out of the box there is an header replacement
for the classification header:
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:
177
9.2. IMPEX
# Classification: Technical details (4593)
$feature1=@Motor diameter, 6752[$clAttrModifiers];
# Motor diameter in millimeter (mm)
Document ID
Sometimes item references lookup method trough attributes does not suffice 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:
INSERT_UPDATE Customer;groups(uid);uid[unique=true];name;defaultPaymentAddress( \&addrID )
;customergroup;andrew@hybhub.com;Andrew;addr1
INSERT Address;\&addrID;owner(Customer.uid);
;addr1;andrew@hybhub.com;
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:
INSERT_UPDATE Media;code[unique=true];realfilename;@media[translator=de.hybris.platform.impe ⌋
֒→
x.jalo.media.MediaDataTranslator];mime[default=’image/jpeg’];$catalogVersion
;/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. An example importing a
saved query follows below.
INSERT_UPDATE SavedQuery;code[unique=true];resulttype(code);query;params(key,value(code))
;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 can
find the referenced item from multiple attributes. You can, in this case, give the Impex attribute
178
CHAPTER 9. PLATFORM CORE
different options. Below is an example with the address owner type which is set to ItemType:
INSERT_UPDATE Address;lastname;owner( Principal.uid | AbstractOrder.code )
;Robert;robert@hybhub.com
;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.
Access properties from Impex
If you need to access your .properties configuration from an Impex file there is away to do it with
the ConfigPropertyImportProcessor class.
/**
* Impex ImportProcessor that injects all config properties as impex definitions.
* All defined configuration properties are added as impex macro definitions with
* the prefix of "config-". For example the config key <tt>mail.smtp.server</tt>
* can be accessed via the macro <tt>$config-mail.smtp.server</tt>.
* In order to use this import processor and to load the configuration properties
* the following must be added to the top of the impex file:
*
* <tt>UPDATE GenericItem[processor=de.hybris.platform.commerceservices.impex.impl.ConfigPro ⌋
pertyImportProcessor];pk[unique=true]</tt>
֒→
*/
So for example, in your local.properties you have the following configuration:
my.default.language=French
In your Impex, you access it using the following syntax:
9.3. SPRING CONTEXT
179
UPDATE GenericItem[processor=de.hybris.platform.commerceservices.impex.impl.ConfigPropertyIm ⌋
portProcessor];pk[unique=true]
֒→
$defaultLanguage=$config-my.default.language
INSERT_UPDATE Country;isocode[unique=true];name[lang=en];active[default=true]
;FR;$defaultLanguage
You can access any properties using the prefix "$config-"
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 configuratio
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.
180
CHAPTER 9. PLATFORM CORE
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:
<typegroup name="hybhub">
<itemtype code="DeactivateOutdatedProductCronJob" extends="CronJob">
<description>Job to deactivate out-dated products</description>
<attributes>
<attribute type="java.util.Date" qualifier="minLastUpdate">
<persistence type="property" />
</attribute>
</attributes>
</itemtype>
</typegroup>
Then we need to create the actual job that deactivate products based on the minLastUpdate
attribute:
181
9.4. CRONJOBS
package com.hybhub.job;
import
import
import
import
import
import
import
import
import
import
de.hybris.platform.catalog.CatalogVersionService;
de.hybris.platform.catalog.enums.ArticleApprovalStatus;
de.hybris.platform.core.model.product.ProductModel;
de.hybris.platform.cronjob.enums.CronJobResult;
de.hybris.platform.cronjob.enums.CronJobStatus;
de.hybris.platform.servicelayer.cronjob.AbstractJobPerformable;
de.hybris.platform.servicelayer.cronjob.PerformResult;
de.hybris.platform.servicelayer.model.ModelService;
de.hybris.platform.servicelayer.search.FlexibleSearchQuery;
de.hybris.platform.servicelayer.search.FlexibleSearchService;
import java.util.List;
import javax.annotation.Resource;
import com.hybhub.model.DeactivateOutdatedProductCronJobModel;
public class DeactivateOutdatedProductJob extends
֒→
AbstractJobPerformable<DeactivateOutdatedProductCronJobModel>
{
@Resource
private FlexibleSearchService flexibleSearchService;
@Resource
private CatalogVersionService catalogVersionService;
@Resource
private ModelService modelService;
֒→
@Override
public PerformResult perform(final DeactivateOutdatedProductCronJobModel cronjob)
{
final FlexibleSearchQuery fsq = new FlexibleSearchQuery("SELECT {pk} FROM
{Product} "
+ "WHERE {modifiedtime} <= ?minLastUpdate " + " AND
{catalogVersion} = ?catalogVersion");
֒→
fsq.addQueryParameter("minLastUpdate", cronjob.getMinLastUpdate());
fsq.addQueryParameter("catalogVersion",
catalogVersionService.getCatalogVersion("electronicsProductCatalog", "Staged"));
֒→
final List<ProductModel> productsToUpdate =
flexibleSearchService.<ProductModel> search(fsq).getResult();
֒→
productsToUpdate.stream().forEach((prd) -> {
prd.setApprovalStatus(ArticleApprovalStatus.UNAPPROVED);
modelService.save(prd);
});
return new PerformResult(CronJobResult.SUCCESS, CronJobStatus.FINISHED);
}
}
182
CHAPTER 9. PLATFORM CORE
You now need to create a Spring bean:
<bean id="deactivateOutdatedProductJob" class="com.hybhub.job.DeactivateOutdatedProductJob"
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 !
import com.hybhub.model.DeactivateOutdatedProductCronJobModel
import de.hybris.platform.cronjob.model.JobModel
import de.hybris.platform.cronjob.model.TriggerModel
def modelService = spring.getBean("modelService")
def cronJobService = spring.getBean("cronJobService")
def flexibleSearchService = spring.getBean("flexibleSearchService")
JobModel job = new JobModel();
job.setCode("deactivateOutdatedProductJob")
job = flexibleSearchService.getModelByExample(job)
DeactivateOutdatedProductCronJobModel cron =
modelService.create(DeactivateOutdatedProductCronJobModel.class)
cron.setMinLastUpdate(new Date())
cron.setCode("deleteOutdatedProductsss")
cron.setJob(job)
modelService.save(cron)
TriggerModel trigger = modelService.create(TriggerModel.class)
trigger.setSecond(0)
trigger.setMinute(1)
trigger.setHour(0)
trigger.setDay(0)
trigger.setMonth(-1)
trigger.setYear(-1)
trigger.setCronJob(cron)
cronJobService.performCronJob(cron)
Be careful this will change the status of all your products under the staged electronic
product catalog !
Abortable Cronjob
Sometimes when the jobs you are performing are time consuming you need to be able to abort a
running cronjob. By default a cronjob will run until it’s done; but you can implement your own
9.5. CLUSTER
183
logic to give it a chance to abort itself. First you need to create a job to be aware of this new
functionality. To do so, there are two methods:
1. override isAbortable()
@Override
public boolean isAbortable()
{
return true;
}
2. configure the Spring bean
<bean id="MyJob" class="de.hybhub.cronjobs.MyJob"
parent="abstractJobPerformable" >
<property name="abortable" value="true"/>
</bean>
Secondly you need to add within your perform method implementation an exit door like this:
if (clearAbortRequestedIfNeeded(theJob))
{
return new PerformResult(CronJobResult.ERROR, CronJobStatus.ABORTED);
}
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;
• cronjobs / events for specific nodes;
• session fail over;
• 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
184
CHAPTER 9. PLATFORM CORE
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 sends a request (TCP or UDP depends on your cluster configuration) so that
other nodes discards the item and reloads it from the database the next time it needs to access
that object.
Configuration
Node specific configuration can be done by using:
#cluster.<nodeid>.my.property=value
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:
clustermode=true
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 keeps track of each nodes
within the database:
clustermode=true
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
Testing
SAP Hybris uses Junit to run unit tests and integration tests, which are located within the testsrc
and web/testsrc folders.
You can execute tests from your IDE or from ant.
9.6. TESTING
185
#All tests
ant alltests
#All web tests
ant allwebtests
#Integration tests
ant integrationtests
#Unit tests
ant unittests
There are other ant commands (manual tests, performance tests...) to see all available
tests execute "ant -p"
Unit tests
Unit tests are simple tests that do not need any access to SAP Hybris platform (database, services...). They focus on testing the correct behavior of a single java class. When necessary, you
can isolate the class by using Mockito to mock anything you need (interfaces, pojo...).
An example of a Unit test class generated by SAP Hybris follows:
186
CHAPTER 9. PLATFORM CORE
/**
* JUnit Tests for the Ruleenginetrail extension.
*/
public class RuleenginetrailTest extends HybrisJUnit4TransactionalTest
{
/** Edit the local|project.properties to change logging behavior (properties
֒→
log4j2.logger.*). */
@SuppressWarnings("unused")
private static final Logger LOG = LoggerFactory.getLogger(RuleenginetrailTest.class);
@Before
public void setUp()
{
// implement here code executed before each test
}
@After
public void tearDown()
{
// implement here code executed after each test
}
/**
* This is a sample test method.
*/
@Test
public void testRuleenginetrail()
{
final boolean testTrue = true;
assertThat(testTrue).isTrue();
}
}
An example of a unit test using Mockito is below:
9.6. TESTING
187
@Test
public void testThrowAnExceptionWhenNotEmptyContentCatalogs() throws BusinessException
{
final ContentCatalogModel contentCatalogOne =
֒→
Mockito.mock(ContentCatalogModel.class);
final CatalogVersionModel catalogVersion = Mockito.mock(CatalogVersionModel.class);
֒→
֒→
֒→
֒→
BDDMockito.given(siteModel.getStores()).willReturn(Collections.EMPTY_LIST);
BDDMockito.given(siteModel.getContentCatalogs()).willReturn(Arrays.asList(contentCat ⌋
alogOne));
BDDMockito.given(contentCatalogOne.getActiveCatalogVersion()).willReturn(catalogVers ⌋
ion);
final Throwable expected = new IllegalStateException("blah");
Mockito.doThrow(expected).when(catalogVersionService)
.setSessionCatalogVersions(Mockito.argThat(new
CollectionArgumentMatcher<CatalogVersionModel>(catalogVersion)));
try
{
strategy.activate(siteModel);
Assert.fail("Should call a setSessionCatalogVersions with content catalogs
from site ");
}
catch (final BaseSiteActivationException ike)
{
Assert.assertEquals(expected, ike.getCause());
//
}
}
Integration tests
Integration tests let you interact with SAP Hybris (database, services...) using a dedicated tenant
junit.
The easiest way to create integration tests is to extend:
• ServicelayerTest, this way you can import any service using the @Resource annotation and
gain access to methods too create basic data (createDefaultUsers, createHardwareCatalog,
createDefaultCatalog...);
• ServiceLayerTransactionalTest is only adding transaction-based isolation logic to your tests.
When you integration test is done the transaction is rolled back.
Other tests
• @DemoTest;
• @PerformanceTest;
• @ManualTest.
188
CHAPTER 9. PLATFORM CORE
Chapter 10
PCM and price
189
190
CHAPTER 10. PCM AND 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) :
• 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
10.2. TAXES
191
• 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
192
CHAPTER 10. PCM AND PRICE
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
10.4. MEDIA OBJECT
193
• 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 :
<alias name="acceleratorImageFormatMapping" alias="imageFormatMapping"/>
<bean id="acceleratorImageFormatMapping" parent="defaultImageFormatMapping">
<property name="mapping">
<map>
<entry key="superZoom" value="1200Wx1200H"/>
<entry key="zoom" value="515Wx515H"/>
<entry key="store" value="365Wx246H"/>
<entry key="product" value="300Wx300H"/>
<entry key="thumbnail" value="96Wx96H"/>
<entry key="cartIcon" value="65Wx65H"/>
<entry key="styleSwatch" value="30Wx30H"/>
</map>
</property>
</bean>
194
CHAPTER 10. PCM AND PRICE
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.
media.default.secured=false
To secure all media turn configure it to true, if you need to secure only one folder you can use :
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)
Warning!
A catalog can have multiple versions and a Synchronization could merge two Staged catalog
into one Online catalog.
10.6. WORKFLOW
195
To create a new CatalogVersionSyncJob from an Impex query :
$productCatalog=productCatalog
$defaultCurrency=EUR
$languages=en
$defaultLanguage=en
$prices=europe1prices[translator=de.hybris.platform.europe1.jalo.impex.Europe1PricesTranslat ⌋
֒→
or]
$stagedProduct=catalogVersion(catalog(id[default=$productCatalog]),version[default=’Staged’] ⌋
֒→
)[unique=true,default=’$productCatalog:Staged’]
$onlineProduct=catalogVersion(catalog(id[default=$productCatalog]),version[default=’Online’] ⌋
֒→
)[unique=true,default=’$productCatalog:Online’]
$sourceProductCV=sourceVersion(catalog(id[default=$productCatalog]),version[default=’Staged’ ⌋
])[unique=true,default=’$productCatalog:Staged’]
֒→
$targetProductCV=targetVersion(catalog(id[default=$productCatalog]),version[default=’Online’ ⌋
֒→
])[unique=true,default=’$productCatalog:Online’]
INSERT_UPDATE CatalogVersionSyncJob;code[unique=true];$sourceProductCV;$targetProductCV;
;sync productCatalog:Staged->Online;;;;
Dependent Synchronization
To avoid having references to a staged catalog in your online catalog version when two catalogs
depend on each other (for example a product catalog and category catalog) you can run a dependent
synchronization.
The CatalogVersionSyncJob item type has two attributes for this :
• dependentSyncJobs
• dependsOnSyncJobs
You can use one or the other, what’s important is to have dependency set between the two synchronization jobs.
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
196
CHAPTER 10. PCM AND PRICE
• 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 11
User Management
197
198
CHAPTER 11. 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
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 :
$START_USERRIGHTS
Type;UID;MemberOfGroups;Password;Target;read;change;create;delete;change_perm
UserGroup;employeegroup;;
;;;;Product;+;-;-;-;;;;;CMSItem.name;+;-;-;-;$END_USERRIGHTS
11.2. SEARCH RESTRICTIONS
199
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 :
import de.hybris.platform.servicelayer.security.permissions.PermissionAssignment
def
def
def
def
userService = spring.getBean("userService")
pcs = spring.getBean("permissionCheckingService")
typeService = spring.getBean("typeService")
pms = spring.getBean("permissionManagementService")
def productmanager = userService.getUserForUID("productmanager")
println pcs.checkTypePermission("Product", productmanager, "read").getCheckValue()
PermissionAssignment permission =
new PermissionAssignment("read", productmanager, true)
pms.addTypePermission(typeService.getComposedTypeForCode("Product")
, permission)
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
200
CHAPTER 11. USER MANAGEMENT
To deactivate search restriction use de.hybris.platform.search. restriction.SearchRestrictionService.e
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
def typeService = spring.getBean("typeService")
def userService = spring.getBean("userService")
def modelService = spring.getBean("modelService")
def restrictedType = typeService.getComposedTypeForCode("Product");
def principal = userService.getUserForUID("anonymous");
def searchRestriction = modelService.create("SearchRestriction");
searchRestriction.setCode("OnlyPublicProduct");
searchRestriction.setActive(Boolean.TRUE);
searchRestriction.setQuery("{code} like ’11%’");
searchRestriction.setRestrictedType(restrictedType);
searchRestriction.setPrincipal(principal);
searchRestriction.setGenerate(Boolean.TRUE);
modelService.save(searchRestriction);
Impex example
INSERT_UPDATE SearchRestriction;code[unique=true];name[lang=en];query;principal(UID);restric ⌋
tedType(code);active;generate
֒→
;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
11.3. B2B HIERARCHY
201
• 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.
202
CHAPTER 11. USER MANAGEMENT
Chapter 12
Study tips
203
204
CHAPTER 12. 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 to plan how you envision it :
1. I setup a V6.2 local environment
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
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.
12.4. UNDERSTAND THE QUESTIONS
205
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.
206
CHAPTER 12. STUDY TIPS
Chapter 13
Mock exam 1
207
208
CHAPTER 13. 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
−→ Go to the 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
−→ Go to the solution.
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
−→ Go to the 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
−→ Go to the solution.
13.1. QUESTIONS
209
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
−→ Go to the 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
−→ Go to the 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
−→ Go to the 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
−→ Go to the solution.
210
CHAPTER 13. MOCK EXAM 1
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
−→ Go to the 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
−→ Go to the 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
−→ Go to the solution.
Mock 1 - Question 12
OAUTH2 is
1. a library built by SAP Hybris to handle authentication
2. a library built by Spring to handle authentication
3. an application protocol like HTTP but for authorization
4. an authorization protocol
−→ Go to the solution.
13.1. QUESTIONS
Mock 1 - Question 13
To load a localized resource bundle, what service should you use ?
1. L10NService
2. I18NService
3. CommonI18NService
4. CommerceCommonI18NService
−→ Go to the 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
−→ Go to the solution.
Mock 1 - Question 15
What are the logging framework shipped with Hybris ?
1. LOG4J
2. LOG4J2
3. LOG4J3
4. SLF4J
−→ Go to the solution.
Mock 1 - Question 16
What happen when you run the following Impex script when the currency doesn’t exist yet ?
UPDATE Currency;isocode[unique=true];conversion;digits;symbol
;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
−→ Go to the solution.
211
212
CHAPTER 13. MOCK EXAM 1
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
−→ Go to the 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
−→ Go to the solution.
Mock 1 - Question 19
What template do you use do create a new cockpit ?
1. ycockpit
2. cockpit
3. ybackoffice
4. backoffice
−→ Go to the 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.xm
2. cockpitextension/resources/cockpitextension/cscockpit/cockpitgroup/listViewContentBrowser_CatalogVersion
3. cockpitextension/resources/cockpitextension-admin/cscockpit/cockpitgroup/listViewContentBrowser.xml
4. cockpitextension/resources/cockpitextension-config/cscockpit/cockpitgroup/listViewContentBrowser_CatalogV
−→ Go to the solution.
13.1. QUESTIONS
213
Mock 1 - Question 21
Which methods are valid to create and save a new product item from the service layer ?
1.
ModelService modelService = spring.getBean("modelService");
ProductModel prd = new ProductModel();
//Fill the product object with valid data
modelService.save(prd);
2.
ModelService modelService = spring.getBean("modelService");
ProductModel prd = modelService.create("Product");
//Fill the product object with valid data
modelService.save(prd);
3.
ModelService modelService = spring.getBean("modelService");
ProductService productService = spring.getBean("productService");
//Assuming we load a valid product
ProductModel prdTemplate = productService.getProductForCode("000001")
ProductModel prd = modelService.clone(prdTemplate)
//Set all unique data
modelService.save(prd);
−→ Go to the 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 springitems.xml files, the update mechanism makes sure that all data that existed in the system before
the update is still accessible after the update
−→ Go to the 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 ?
INSERT_UPDATE Currency;isocode[unique=true];conversion;digits;symbol
;DKK;1;2;DKK
214
CHAPTER 13. MOCK EXAM 1
INSERT Currency;isocode[unique=true];conversion;digits;symbol
;DKK;7;2;DKK
INSERT_UPDATE Currency;isocode[unique=true];conversion;digits
;VND;7;2;VND
1. none
2. one
3. two
4. three
−→ Go to the 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
−→ Go to the solution.
Mock 1 - Question 25
Is this a valid item type definition ?
<itemtype code="DeactivateOutdatedProductCronJob">
<description>Job to deactivate out-dated products</description>
<attributes>
<attribute type="java.util.Date" qualifier="minLastUpdate">
<persistence type="memory" />
</attribute>
</attributes>
</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
−→ Go to the solution.
13.1. QUESTIONS
215
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
−→ Go to the solution.
Mock 1 - Question 27
What SQL query could be generated from the following flexible search query ?
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 (?,?))
−→ Go to the solution.
Mock 1 - Question 28
Which of the following item type attribute default value definition valid ?
1. <defaultvalue>java.lang.Boolean.FALSE</defaultvalue>
2. enumerationService().getEnumerationValue("validEnumeration", "validValue")
3. <defaultvalue>Boolean.FALSE</defaultvalue>
4. <defaultvalue>com.hybhub.core.ExistingClass.EXISTING_STATIC_STRING</defaultvalue>
−→ Go to the 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
−→ Go to the solution.
216
CHAPTER 13. MOCK EXAM 1
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
−→ Go to the 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
−→ Go to the 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
−→ Go to the 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
−→ Go to the solution.
13.1. QUESTIONS
217
Mock 1 - Question 34
How do you declare an attribute dynamic ?
1.
<attribute type="dynamic" attributeHandler="myAttributeHandlerBean" />
1.
<persistence type="dynamic" attributeHandler="myAttributeHandlerBean" />
1.
<dynamic attributeHandler="myAtttibuteHandlerBean" />
1.
<persistence dynamic="myAtttibuteHandlerBean" />
−→ Go to the 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
−→ Go to the 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
−→ Go to the 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
−→ Go to the solution.
218
CHAPTER 13. MOCK EXAM 1
Mock 1 - Question 38
In order to test a dao implementation what test should you write ?
1. @UnitTest
2. @DatabaseTest
3. @SqlTest
4. @IntegrationTest
−→ Go to the 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=<CHANGE_ME> assuming the env variable exists and is name y_hybhub_config
4. using hybhub.config=
? assuming the env variable exists and is name hybhub_config
−→ Go to the solution.
Mock 1 - Question 40
What statements are correct about he following impex ?
INSERT_UPDATE MediaFolder;qualifier[unique=true];path[unique=true]
;images;images
;email-body;email-body
;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
−→ Go to the 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’
−→ Go to the solution.
13.1. QUESTIONS
219
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
−→ Go to the 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
−→ Go to the 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
−→ Go to the 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
−→ Go to the solution.
220
CHAPTER 13. MOCK EXAM 1
Mock 1 - Question 46
How many transactions would be created by the following Groovy script ?
def transaction = de.hybris.platform.tx.Transaction.current()
transaction.begin()
transaction.begin()
//Do something
transaction.commit()
transaction.begin()
//Do something
transaction.commit()
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
−→ Go to the solution.
Mock 1 - Question 47
What is the main entry servlet of Spring MVC application ?
1. SpringMvcServlet
2. DispatcherServlet
3. JaloServlet
4. RequestContextServlet
−→ Go to the 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
−→ Go to the solution.
13.1. QUESTIONS
221
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
−→ Go to the 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
−→ Go to the solution.
Mock 1 - Question 51
Choose the best definition for the following exception : de.hybris.platform.servicelayer.exceptions.AmbiguousIdentifierExcep
?
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
−→ Go to the 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
−→ Go to the solution.
222
CHAPTER 13. MOCK EXAM 1
Mock 1 - Question 53
The Spring Integration Framework is used for ?
1. OCC webservices
2. Datahub
3. Hot Folder
4. Service Layer
−→ Go to the 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
−→ Go to the 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
−→ Go to the 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
−→ Go to the solution.
13.1. QUESTIONS
223
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
−→ Go to the 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
−→ Go to the solution.
Mock 1 - Question 59
Which of the following interceptors are valid ?
1. load
2. init
3. prepare
4. remove
−→ Go to the solution.
Mock 1 - Question 60
What statements are 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
−→ Go to the solution.
224
CHAPTER 13. MOCK EXAM 1
Mock 1 - Question 61
A Media can be ?
1. a image
2. a zip file
3. a flat file
4. a string
−→ Go to the 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
−→ Go to the 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 ?
{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
−→ Go to the solution.
Mock 1 - Question 64
What happened when you execute the following Groovy script ?
import java.util.HashSet
import de.hybris.platform.core.model.user.UserGroupModel
def modelService = spring.getBean("modelService")
def group = modelService.create("userGroup")
group.setUid("newGroup")
modelService.save(group)
def groups = new HashSet<UserGroupModel>()
13.1. QUESTIONS
groups.add(group)
def customer = modelService.create("customer")
customer.setUid("newCustomer")
customer.setName("newCustomer")
customer.setGroups(groups)
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
−→ Go to the 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
−→ Go to the 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
−→ Go to the 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
−→ Go to the solution.
225
226
CHAPTER 13. MOCK EXAM 1
Mock 1 - Question 68
Why would run the following flexible search query ?
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
−→ Go to the solution.
Mock 1 - Question 69
What is the right way to create a localized string attribute ?
1.
<attribute qualifier="name" type="java.lang.String">
<persistence type="property" localized="true"/>
</attribute>
2.
<attribute qualifier="name" type="localized:String">
<persistence type="property"/>
</attribute>
3.
<attribute qualifier="name" type="localized:java.lang.String">
<persistence type="property" />
</attribute>
4.
<attribute qualifier="name" type="localized:java.lang.String">
</attribute>
−→ Go to the 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
−→ Go to the solution.
13.1. QUESTIONS
Mock 1 - Question 71
What is the purpose of the following class ?
/*
* [y] hybris Platform
*
* Copyright (c) 2000-2016 SAP SE
* All rights reserved.
*
* This software is the confidential and proprietary information of SAP
* Hybris ("Confidential Information"). You shall not disclose such
* Confidential Information and shall use it only in accordance with the
* terms of the license agreement you entered into with SAP Hybris.
*/
package com.hybhub.setup;
import ...
@SystemSetup(extension = HybhubhookConstants.EXTENSIONNAME)
public class HybhubHookSystemSetup extends AbstractSystemSetup
{
֒→
֒→
֒→
final static Logger LOG =
LoggerFactory.getLogger(HybhubHookSystemSetup.class);
@SystemSetupParameterMethod
@Override
public List<SystemSetupParameter> getInitializationOptions()
{
final List<SystemSetupParameter> params = new ArrayList<>();
params.add(createBooleanSystemSetupParameter("key", "Choice",
false));
return params;
}
@SystemSetup(type = Type.ALL, process = Process.ALL)
public void createEssentialData(final SystemSetupContext context)
{
final boolean choice = getBooleanSystemSetupParameter(context,
"choice");
if (choice)
{
//Do something
}
else
{
//Do something else
}
}
227
228
CHAPTER 13. MOCK EXAM 1
}
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
−→ Go to the solution.
Mock 1 - Question 72
Is this a valid impex import ?
INSERT_UPDATE Title;code
#% beforeEach: print(line[1]);
;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
−→ Go to the solution.
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
−→ Go to the solution.
Mock 1 - Question 74
Which are valid steps of the ant all target ?
1. Resolving extensions dependencies
2. Restart the application server
3. Delete all previously compiled classes
4. Generate sources for all extensions
−→ Go to the solution.
13.1. QUESTIONS
229
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
−→ Go to the 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
−→ Go to the solution.
Mock 1 - Question 77
Is this a valid business process definition ?
<?xml version="1.0" encoding="utf-8"?>
<process>
<action id="action1" bean="action1">
<transition name="OK" to="success"/>
<transition name="NOK" to="action2"/>
</action>
<action id="action2" bean="action2">
<transition name="OK" to="error"/>
</action>
<end id="error" state="ERROR">All went wrong.</end>
<end id="success" state="SUCCEEDED">Order placed.</end>
</process>
1. yes
2. yes if you had a new action with start=true
3. yes if action1 implements StartProcess
4. no
−→ Go to the solution.
230
CHAPTER 13. MOCK EXAM 1
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
−→ Go to the 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)
−→ Go to the 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
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.
−→ Go back to the question.
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.
13.2. SOLUTIONS
231
−→ Go back to the question.
Mock 1 - Solution 3
2,4 are correct.
The setantenv scrips configure :
• PLATFORM_HOME
• ANT_OPTS
• ANT_HOME
• add ANT_HOME to your path
−→ Go back to the question.
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.
−→ Go back to the question.
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.
−→ Go back to the question.
Mock 1 - Solution 6
1,3 are correct.
−→ Go back to the question.
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)
−→ Go back to the question.
Mock 1 - Solution 8
*1,2,3,4 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)
−→ Go back to the question.
232
CHAPTER 13. MOCK EXAM 1
Mock 1 - Solution 9
4 is correct.
−→ Go back to the question.
Mock 1 - Solution 10
1 is correct.
−→ Go back to the question.
Mock 1 - Solution 11
2 is correct.
After a header all lines would be imported (unless they are empty, contain comments or macro).
−→ Go back to the question.
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.
−→ Go back to the question.
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
−→ Go back to the question.
Mock 1 - Solution 14
3 is correct.
−→ Go back to the question.
Mock 1 - Solution 15
2 is correct.
SLF4J is a simple logging facade for logging frameworks.
−→ Go back to the question.
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.
−→ Go back to the question.
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.
13.2. SOLUTIONS
233
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.
−→ Go back to the question.
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.
−→ Go back to the question.
Mock 1 - Solution 19
1 is correct.
−→ Go back to the question.
Mock 1 - Solution 20
4 is correct.
Remember extensionName/resources/extensionName-config/userGroup/context_itemType.xml
−→ Go back to the question.
Mock 1 - Solution 21
1,2,3 are correct
−→ Go back to the question.
Mock 1 - Solution 22
1 is correct.
−→ Go back to the question.
Mock 1 - Solution 23
2 is correct.
INSERT Currency;isocode[unique=true];conversion;digits
;DKK;7;2;DKK
would fail since because it’s conflicting with an existing item (de.hybris.platform.impex.jalo.imp.ItemConflictException)
−→ Go back to the question.
Mock 1 - Solution 24
2,4 are correct.
−→ Go back to the question.
Mock 1 - Solution 25
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.
−→ Go back to the question.
Mock 1 - Solution 26
3 is correct.
−→ Go back to the question.
Mock 1 - Solution 27
2 is correct.
234
CHAPTER 13. MOCK EXAM 1
−→ Go back to the 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().
−→ Go back to the question.
Mock 1 - Solution 29
2,3 are correct.
have a look at de.hybris.platform.servicelayer.model.ModelService.
−→ Go back to the question.
Mock 1 - Solution 30
1,3 are correct.
−→ Go back to the question.
Mock 1 - Solution 31
1,3 are correct.
−→ Go back to the question.
Mock 1 - Solution 32
1 is correct.
−→ Go back to the question.
Mock 1 - Solution 33
2,3,4 are correct.
−→ Go back to the question.
Mock 1 - Solution 34
2 is correct.
−→ Go back to the question.
Mock 1 - Solution 35
4 is correct.
−→ Go back to the question.
Mock 1 - Solution 36
3 is correct.
−→ Go back to the question.
Mock 1 - Solution 37
2 is correct.
−→ Go back to the question.
Mock 1 - Solution 38
4 is correct.
−→ Go back to the question.
Mock 1 - Solution 39
3 is correct.
13.2. SOLUTIONS
235
−→ Go back to the question.
Mock 1 - Solution 40
3,4 are correct.
−→ Go back to the question.
Mock 1 - Solution 41
1 is correct.
−→ Go back to the question.
Mock 1 - Solution 42
3 is correct.
Capture, is the action of transferring money into the merchant account after it has been authorized.
−→ Go back to the question.
Mock 1 - Solution 43
2 is correct.
1,2 don’t respect the conveniont (essentialdata*.impex) 3 project data are not being imported
in this scenario.
−→ Go back to the question.
Mock 1 - Solution 44
1 is correct.
−→ Go back to the question.
Mock 1 - Solution 45
4 is correct.
−→ Go back to the question.
Mock 1 - Solution 46
2 is correct.
Remember that only one transaction per thread can be created.
−→ Go back to the question.
Mock 1 - Solution 47
2 is correct.
−→ Go back to the question.
Mock 1 - Solution 48
1,3 are correct.
−→ Go back to the question.
Mock 1 - Solution 49
3 is correct.
−→ Go back to the question.
Mock 1 - Solution 50
4 is correct.
−→ Go back to the question.
Mock 1 - Solution 51
2 is correct.
236
CHAPTER 13. MOCK EXAM 1
−→ Go back to the question.
Mock 1 - Solution 52
1 is correct.
−→ Go back to the question.
Mock 1 - Solution 53
3 is correct.
−→ Go back to the question.
Mock 1 - Solution 54
2 is correct.
−→ Go back to the question.
Mock 1 - Solution 55
1 is correct.
−→ Go back to the question.
Mock 1 - Solution 56
4 is correct.
−→ Go back to the 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.
−→ Go back to the question.
Mock 1 - Solution 58
3 is correct.
−→ Go back to the question.
Mock 1 - Solution 59
1,2,3,4 are correct.
−→ Go back to the question.
Mock 1 - Solution 60
1,3,4 are correct.
−→ Go back to the question.
Mock 1 - Solution 61
1,2,3 are correct.
−→ Go back to the question.
Mock 1 - Solution 62
4 is correct.
−→ Go back to the question.
Mock 1 - Solution 63
3 is correct.
13.2. SOLUTIONS
237
−→ Go back to the question.
Mock 1 - Solution 64
4 is correct.
−→ Go back to the question.
Mock 1 - Solution 65
1,3 are correct.
−→ Go back to the question.
Mock 1 - Solution 66
1 is correct.
−→ Go back to the question.
Mock 1 - Solution 67
4 is correct.
1 is wrong since SAP Hybris V6 Apache SOLR is running in its own process.
−→ Go back to the question.
Mock 1 - Solution 68
2 is correct.
−→ Go back to the question.
Mock 1 - Solution 69
3 is correct.
4 is wrong, persistence is mandatory.
−→ Go back to the question.
Mock 1 - Solution 70
2,3,4 are correct.
−→ Go back to the question.
Mock 1 - Solution 71
3 is correct.
−→ Go back to the 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.
−→ Go back to the question.
Mock 1 - Solution 73
1 is correct.
−→ Go back to the question.
Mock 1 - Solution 74
1,2,4 are correct.
−→ Go back to the question.
Mock 1 - Solution 75
3,4 are correct.
238
CHAPTER 13. MOCK EXAM 1
−→ Go back to the question.
Mock 1 - Solution 76
3 is correct.
−→ Go back to the question.
Mock 1 - Solution 77
4 is correct.
Missing start="startAction" name="processName" processClass="Process.Class"
−→ Go back to the 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.
−→ Go back to the question.
Mock 1 - Solution 79
4 is correct.
−→ Go back to the question.
Mock 1 - Solution 80
3 is correct.
Chapter 14
Mock exam 2
239
240
CHAPTER 14. MOCK EXAM 2
Questions
Mock 2 - Question 1
What is/are the best definition(s) of 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
−→ Go to the solution.
Mock 2 - Question 2
What changes need to be done in the following query to be imported successfully ?
\$productCatalog=apparelProductCatalog
\$productCatalogName=Apparel Product Catalog
INSERT_UPDATE
֒→
ApparelProduct;code;\$catalogVersion;unit(code);supercategories(code,\$catalogVersion)
;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]
4. use the type Product instead of ApparelProduct
−→ Go to the 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
−→ Go to the solution.
14.1. QUESTIONS
241
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
−→ Go to the 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
−→ Go to the 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
−→ Go to the solution.
Mock 2 - Question 7
What is wrong with the following item type definition ?
<itemtype code="Subscription" extends="GenericItem">
<attributes>
<attribute type="java.lang.String" qualifier="code">
<persistence type="property" />
<modifiers unique="true"/>
</attribute>
</attributes>
<indexes>
<index name="codeIdx">
<key attribute="code"/>
</index>
</indexes>
</itemtype>
242
CHAPTER 14. MOCK EXAM 2
1. A Jalo class definition is missing
2. An index needs to be on at least two attributes
3. GenericItem is not a valid item to extend from
4. A deployment table specification is missing
−→ Go to the 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
−→ Go to the solution.
Mock 2 - Question 9
What steps do you need to fulfill in order to create a new cronjob ?
1. create a new cron job expression in your Spring XML
2. implement a job in Java
3. create a new item type extending CronJob
4. add the new cronjob in your local.properties
−→ Go to the solution.
Mock 2 - Question 10
What statements are wrong about catalog 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 version can be a target and a source
−→ Go to the solution.
14.1. QUESTIONS
243
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
−→ Go to the 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
−→ Go to the 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
−→ Go to the 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
−→ Go to the solution.
244
CHAPTER 14. MOCK EXAM 2
Mock 2 - Question 15
When you create the following item type A what classes are being generated ?
<itemtype code="A" extends="ItemB" generate="false">
<attributes>
<attribute type="java.lang.String" qualifier="code">
<persistence type="property" />
<modifiers unique="true"/>
</attribute>
</attributes>
</itemtype>
1. A.java
2. GeneratedA.java
3. AJalo.java
4. AModel.java
−→ Go to the 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
−→ Go to the 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 <tenantid>.allowed.extensions and <tenantid>.forbidden.extensions inside your
configuration
4. no, SAP Hybris is not compatible with this
−→ Go to the solution.
14.1. QUESTIONS
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
−→ Go to the solution.
Mock 2 - Question 19
Is this a valid Flexible Search Query ?
select {p.description[fr]:o} from {Product as p} where {p:pk} in
( {{ 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
−→ Go to the 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
−→ Go to the 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
−→ Go to the solution.
245
246
CHAPTER 14. MOCK EXAM 2
Mock 2 - Question 22
What is highest B2B organization block ?
1. company
2. unit
3. division
4. region
−→ Go to the solution.
Mock 2 - Question 23
In order to force a product to be listed on top of a given category, what out of the box feature(s)
should you use ?
1. boost rules
2. hero rules
3. hero products
4. top products
−→ Go to the solution.
Mock 2 - Question 24
What payment steps are described by the following definition ?
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
−→ Go to the solution.
Mock 2 - Question 25
For what of the following things can the BTG module be used?
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
−→ Go to the solution.
14.1. QUESTIONS
247
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
−→ Go to the solution.
Mock 2 - Question 27
What Spring context has the largest scope ?
1. web context
2. core context
3. shared context
4. international context
−→ Go to the solution.
Mock 2 - Question 28
What will happen during an ImpEx Import 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
−→ Go to the 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
−→ Go to the solution.
248
CHAPTER 14. MOCK EXAM 2
Mock 2 - Question 30
What is the problem with the following business process action ?
package com.hybhub.core.process.action;
import
import
import
import
import
de.hybris.platform.core.model.order.OrderModel;
de.hybris.platform.orderprocessing.model.OrderProcessModel;
de.hybris.platform.processengine.action.AbstractSimpleDecisionAction;
de.hybris.platform.servicelayer.model.ModelService;
de.hybris.platform.task.RetryLaterException;
import javax.annotation.Resource;
public class HybhubSimpleAction extends
֒→
AbstractSimpleDecisionAction<OrderProcessModel>
{
@Resource
private ModelService modelService;
֒→
@Override
public Transition executeAction(final OrderProcessModel orderProcess)
throws RetryLaterException, Exception
{
OrderModel order = orderProcess.getOrder();
if(order!= null){
order.setNet(Boolean.TRUE);
modelService.save(order);
return Transition.OK;
}
return null;
}
}
1. it doesn’t always return a transition
2. it has not setter for the modelService attribute
3. it should implement Action<T>
4. the package is wrong
−→ Go to the solution.
Mock 2 - Question 31
What is true about the DefaultCMSComponentController controller ?
1. it will inject all attributes into the model
14.1. QUESTIONS
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
−→ Go to the solution.
Mock 2 - Question 32
What is true about the following log extracted from the build process ?
[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
−→ Go to the solution.
Mock 2 - Question 33
Choose the correct user rights definition to complete the following import query.
\$START_USERRIGHTS
Type;UID;MemberOfGroups;Password;Target;read;change;create;delete;change_perm
UserGroup;employeegroup;;
<Choose the right answer to complete this>
\$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
−→ Go to the solution.
Mock 2 - Question 34
Which of the following components are deprecated ?
1. cockpit framework
2. Jalo layer
3. task engine
4. service layer
−→ Go to the solution.
249
250
CHAPTER 14. MOCK EXAM 2
Mock 2 - Question 35
What is the correct way of configuring a new logger for the package com.hybhub.hybhubaddon ?
1.
log4j.logger.com.hybhub.hybhubaddon = info
2.
log4j.logger.hybhub.name = com.hybhub.hybhubaddon
log4j.logger.hybhub.level = info
log4j.logger.hybhub.appenderRef.stdout.ref = STDOUT
3.
log4j2.logger.hybhub.name = com.hybhub.hybhubaddon
log4j2.logger.hybhub.level = info
log4j2.logger.hybhub.appenderRef.stdout.ref = STDOUT
4.
log4j2.logger.com.hybhub.hybhubaddon = info
log4j2.logger.com.hybhub.hybhubaddon = STDOUT
−→ Go to the solution.
Mock 2 - Question 36
The OCC webservices are ?
1. restful API
2. restless API
3. soap API
4. oAuth API
−→ Go to the 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
−→ Go to the solution.
14.1. QUESTIONS
251
Mock 2 - Question 38
What is wrong with the following extensioninfo.xml file ?
<extensioninfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
֒→
xsi:noNamespaceSchemaLocation="extensioninfo.xsd">
<extension abstractclassprefix="Generated" classprefix="HybhubFacades"
֒→
name="hybhubfacades">
<requires-extension name="hybhubfacades"/>
<requires-extension name="hybhubcore"/>
<coremodule generated="true"
֒→
manager="de.hybris.platform.jalo.extension.GenericManager"
packageroot="com.hybhub.facades"/>
֒→
</extension>
</extensioninfo>
1. missing web module declaration
2. missing core module declaration
3. missing hmc module declaration
4. dependency issue
−→ Go to the solution.
Mock 2 - Question 39
Is the following dynamic attribute handler correct ?
package com.hybhub.core.model.dynamic;
import de.hybris.platform.core.model.product.ProductModel;
import de.hybris.platform.servicelayer.model.attribute.DynamicAttributeHandler;
public class HybhubDynamicHandler implements DynamicAttributeHandler<String,
֒→
ProductModel>
{
@Override
public String get(ProductModel product)
{
return product.getCode() + " - " + product.getDescription();
}
}
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
−→ Go to the solution.
252
CHAPTER 14. MOCK EXAM 2
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
−→ Go to the 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
−→ Go to the solution.
Mock 2 - Question 42
What is the following Spring configuration doing ?
<context:annotation-config/>
<context:component-scan
base-package="...,..."
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
−→ Go to the 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
−→ Go to the solution.
14.1. QUESTIONS
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
−→ Go to the solution.
Mock 2 - Question 45
Select the existing Impex header mode.
1. INSERTED
2. UPDATE_INSERT
3. REMOVE
4. DELETE
−→ Go to the 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
−→ Go to the 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 the Interceptor interface and create a bean from it.
3. run a system update
4. add a Spring bean mapping the item type and the Interceptor implementation
−→ Go to the solution.
253
254
CHAPTER 14. MOCK EXAM 2
Mock 2 - Question 48
A checkout step has ?
1. checkoutGroup reference
2. checkoutStepValidator reference
3. transitions map
4. progressBarId string
−→ Go to the solution.
Mock 2 - Question 49
What are are valid legacy cockpit areas ?
1. navigation
2. item
3. browser
4. editor
−→ Go to the 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
−→ Go to the 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
−→ Go to the solution.
14.1. QUESTIONS
Mock 2 - Question 52
How could you declare configure an attribute to be encrypted ?
1.
<attribute qualifier="sensible" autocreate="true" type="java.lang.String">
<persistence type="property"/>
<modifiers encrypted="true"/>
</attribute>
2.
<attribute qualifier="sensible" autocreate="true"
֒→
type="encrypted:java.lang.String">
<persistence type="property"/>
</attribute>
3.
<attribute qualifier="sensible" autocreate="true" type="java.lang.String">
<persistence type="property" encrypted="true"/>
</attribute>
4.
<attribute qualifier="sensible" autocreate="true" type="java.lang.String">
<modifiers type="property" encrypted="true"/>
</attribute>
−→ Go to the solution.
Mock 2 - Question 53
Which item types exist ?
1. collectiontype
2. enumtype
3. atomictype
4. listtype
−→ Go to the solution.
Mock 2 - Question 54
A customer segment could be executed in ?
1. optimized processing
2. full processing
3. jalo processing
4. complete processing
−→ Go to the solution.
255
256
CHAPTER 14. MOCK EXAM 2
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
−→ Go to the 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
−→ Go to the 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
−→ Go to the 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
−→ Go to the solution.
14.1. QUESTIONS
257
Mock 2 - Question 59
How could you improve the following code (groovy) ?
import de.hybris.platform.processengine.enums.ProcessState
def businessProcessService = spring.getBean("businessProcessService")
def modelService = spring.getBean("modelService")
def process = businessProcessService.createProcess(UUID.randomUUID().toString(),
֒→
"myProcess")
modelService.save(process)
businessProcessService.startProcess(process)
modelService.refresh(process)
if(ProcessState.SUCCEEDED != process.getProcessState()){
businessProcessService.startProcess(process)
}
1. use the method <T extends BusinessProcessModel> 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
−→ Go to the solution.
Mock 2 - Question 60
What statements are true about the following table (SQL DDL for HSQL) ?
CREATE CACHED TABLE b2bbudgetslp
(
ITEMPK BIGINT,
ITEMTYPEPK BIGINT,
LANGPK BIGINT,
p_name NVARCHAR(255),
PRIMARY KEY (ITEMPK, LANGPK)
);
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
−→ Go to the solution.
258
CHAPTER 14. MOCK EXAM 2
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
−→ Go to the 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
−→ Go to the 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
−→ Go to the 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
−→ Go to the solution.
14.1. QUESTIONS
259
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
−→ Go to the 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
−→ Go to the 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
−→ Go to the solution.
Mock 2 - Question 68
Which bean would be loaded from getBean("bean") ?
<bean name="stringBean" class="java.lang.String" >
<constructor-arg><value>my String Name</value></constructor-arg>
</bean>
<bean id="stringBean" class="java.lang.String" >
<constructor-arg><value>my String ID</value></constructor-arg>
</bean>
<alias name="stringBean" alias="bean" />
260
CHAPTER 14. MOCK EXAM 2
1. my String Name
2. my String ID
3. a new String
4. none
−→ Go to the 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
−→ Go to the solution.
Mock 2 - Question 70
What a POS is ?
1. a warehouse
2. a physical store
3. a web store
4. a geolocalization service
−→ Go to the 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
−→ Go to the solution.
14.1. QUESTIONS
261
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
−→ Go to the 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
−→ Go to the 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
−→ Go to the 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
−→ Go to the solution.
262
CHAPTER 14. MOCK EXAM 2
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
−→ Go to the solution.
Mock 2 - Question 77
Choose the flexible query which has generated the following SQL query ?
SELECT item_t0.PK, item_t1.p_code
FROM products item_t0 LEFT JOIN medias item_t1
ON item_t1.PK = item_t0.p_logo
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
−→ Go to the solution.
Mock 2 - Question 78
What service should you use to save an model ?
1. persistenceService
2. jaloService
3. serviceLayerService
4. modelService
−→ Go to the 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
−→ Go to the solution.
14.2. SOLUTIONS
263
Mock 2 - Question 80
With default configuration when you load a model item with the model service (for examples product
model).What is automatically loaded inside the object ?
1. nothing, all attributes are lazy loaded
2. only literal values
3. only reference values
4. all
−→ Go to the solution.
Solutions
Mock 2 - Solution 1
1 and 2 are correct.
−→ Go back to the question.
Mock 2 - Solution 2
1 and 3 are correct.
−→ Go back to the question.
Mock 2 - Solution 3
1 is correct.
−→ Go back to the question.
Mock 2 - Solution 4
3 is correct.
−→ Go back to the question.
Mock 2 - Solution 5
3 and 4 are correct.
When you implement the interface ClusterAwareEvent you need to implement the method publish(int sourceNodeId, int targetNodeId), but you are free to decide whether your code should run
on a very specific node (answer 3) or on all nodes (answer 4). In order to be able to broadcast and
process it to all nodes you need to return true in the publish method like so:
264
CHAPTER 14. MOCK EXAM 2
package com.hyhub.core;
import de.hybris.platform.servicelayer.event.ClusterAwareEvent;
import de.hybris.platform.servicelayer.event.impl.AbstractEventListener;
public class AnyEventListener extends AbstractEventListener<AnyEvent> implements
֒→
ClusterAwareEvent {
@Override
protected void onEvent(AnyEvent event) {
// your logic
}
֒→
֒→
֒→
/**
* Decide weather this event should be broadcasted/received. Examples are
* <ul>
* <li><code>return (sourceNodeId==targetNodeId );</code> => will only publish to
local cluster</li>
* <li><code>return true;</code> => will publish to all nodes</li>
* <li><code>return (targetNodeId==14);</code> => publish to dedicated node
regardless of source</li>
* </ul>
* @return <code>true</code> if event should be published from source cluster node
to target cluster node
*/
@Override
public boolean publish(int sourceNodeId, int targetNodeId) {
// publish event on all cluster nodes
return true;
}
}
−→ Go back to the question.
Mock 2 - Solution 6
2 is correct.
−→ Go back to the question.
Mock 2 - Solution 7
4 is correct.
−→ Go back to the question.
Mock 2 - Solution 8
1,3,4 are correct.
−→ Go back to the question.
Mock 2 - Solution 9
2,3 are correct.
−→ Go back to the question.
Mock 2 - Solution 10
1,2,3 are correct.
14.2. SOLUTIONS
265
−→ Go back to the question.
Mock 2 - Solution 11
1,2,4 are correct.
−→ Go back to the question.
Mock 2 - Solution 12
1 is correct.
−→ Go back to the question.
Mock 2 - Solution 13
1,2,3,4 are correct.
−→ Go back to the question.
Mock 2 - Solution 14
3 is correct.
−→ Go back to the question.
Mock 2 - Solution 15
4 is correct.
generate="false" means that Jalo classes won’t be generated.
−→ Go back to the question.
Mock 2 - Solution 16
3 is correct.
−→ Go back to the question.
Mock 2 - Solution 17
2 is correct.
−→ Go back to the question.
Mock 2 - Solution 18
3 is correct.
−→ Go back to the question.
Mock 2 - Solution 19
4 is correct.
The :o in the SELECT clause means that an OUTER JOIN is used in order to get the localizations.
This would result in a ResultSet containing also items where the selected localization is null.
−→ Go back to the question.
Mock 2 - Solution 20
1 is correct.
−→ Go back to the question.
Mock 2 - Solution 21
1,2 are correct.
−→ Go back to the question.
Mock 2 - Solution 22
2 is correct.
266
CHAPTER 14. MOCK EXAM 2
−→ Go back to the question.
Mock 2 - Solution 23
3 is correct.
−→ Go back to the question.
Mock 2 - Solution 24
2 is correct.
−→ Go back to the question.
Mock 2 - Solution 25
1 is correct.
−→ Go back to the 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.
−→ Go back to the 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.
−→ Go back to the question.
Mock 2 - Solution 28
3 is correct.
−→ Go back to the question.
Mock 2 - Solution 29
1,2,3 are correct.
−→ Go back to the question.
Mock 2 - Solution 30
1 is correct.
−→ Go back to the question.
Mock 2 - Solution 31
2,3 are correct.
−→ Go back to the question.
Mock 2 - Solution 32
1,2,4 are correct.
−→ Go back to the question.
Mock 2 - Solution 33
3 is correct.
−→ Go back to the question.
Mock 2 - Solution 34
1,2 are correct.
14.2. SOLUTIONS
−→ Go back to the question.
Mock 2 - Solution 35
3 is correct.
−→ Go back to the question.
Mock 2 - Solution 36
1 is correct.
−→ Go back to the question.
Mock 2 - Solution 37
2,4 are correct.
−→ Go back to the question.
Mock 2 - Solution 38
4 is correct.
−→ Go back to the question.
Mock 2 - Solution 39
2 is correct.
−→ Go back to the question.
Mock 2 - Solution 40
1,3 is correct.
−→ Go back to the question.
Mock 2 - Solution 41
3 is correct.
−→ Go back to the question.
Mock 2 - Solution 42
2 is correct.
−→ Go back to the question.
Mock 2 - Solution 43
1 is correct.
−→ Go back to the question.
Mock 2 - Solution 44
3 is correct.
−→ Go back to the question.
Mock 2 - Solution 45
3 is correct.
−→ Go back to the question.
Mock 2 - Solution 46
4 is correct.
−→ Go back to the question.
Mock 2 - Solution 47
2,3 are correct.
267
268
−→ Go back to the question.
Mock 2 - Solution 48
1,2,3,4 are correct.
−→ Go back to the question.
Mock 2 - Solution 49
1,3,4 are correct.
−→ Go back to the question.
Mock 2 - Solution 50
3 is correct.
−→ Go back to the question.
Mock 2 - Solution 51
4 is correct.
−→ Go back to the question.
Mock 2 - Solution 52
1 is correct.
−→ Go back to the question.
Mock 2 - Solution 53
1,2,3 are correct.
−→ Go back to the question.
Mock 2 - Solution 54
1,2 are correct.
−→ Go back to the question.
Mock 2 - Solution 55
2 is correct.
−→ Go back to the question.
Mock 2 - Solution 56
1,3 are correct.
−→ Go back to the question.
Mock 2 - Solution 57
1 is correct.
−→ Go back to the question.
Mock 2 - Solution 58
1,4 are correct.
−→ Go back to the question.
Mock 2 - Solution 59
1,2,3 are correct.
−→ Go back to the question.
Mock 2 - Solution 60
3 is correct.
CHAPTER 14. MOCK EXAM 2
14.2. SOLUTIONS
−→ Go back to the question.
Mock 2 - Solution 61
2 is correct.
−→ Go back to the question.
Mock 2 - Solution 62
2 is correct.
−→ Go back to the question.
Mock 2 - Solution 63
3 is correct.
Have a look at the extension template ygroovy.
−→ Go back to the question.
Mock 2 - Solution 64
1,2,4 are correct.
−→ Go back to the question.
Mock 2 - Solution 65
2 is correct.
−→ Go back to the question.
Mock 2 - Solution 66
1,3 are correct.
−→ Go back to the question.
Mock 2 - Solution 67
1,3 are correct.
−→ Go back to the question.
Mock 2 - Solution 68
4 is correct.
−→ Go back to the question.
Mock 2 - Solution 69
3,4 are correct.
−→ Go back to the question.
Mock 2 - Solution 70
2 is correct.
−→ Go back to the question.
Mock 2 - Solution 71
2 and 3 are correct.
−→ Go back to the question.
Mock 2 - Solution 72
3 is correct.
−→ Go back to the question.
Mock 2 - Solution 73
2 is correct.
269
270
CHAPTER 14. MOCK EXAM 2
−→ Go back to the question.
Mock 2 - Solution 74
1,2,4 are correct.
−→ Go back to the question.
Mock 2 - Solution 75
2 is correct.
−→ Go back to the question.
Mock 2 - Solution 76
2 is correct.
−→ Go back to the question.
Mock 2 - Solution 77
3 is correct.
−→ Go back to the question.
Mock 2 - Solution 78
4 is correct.
−→ Go back to the question.
Mock 2 - Solution 79
4 is correct.
−→ Go back to the question.
Mock 2 - Solution 80
1 is correct. Look at the servicelayer.prefetch property inside the advanced.properties file inside
the platform.
There are four available modes :
• none
• literal
• all
• default (equal to none)
−→ Go back to the question.
Chapter 15
Mock exam 3
271
272
CHAPTER 15. MOCK EXAM 3
Questions
Mock 3 - Question 1
Dynamic forms are used to ?
1. Automatically generates html forms from an Hybris model object
2. Executes dynamic actions on attributes, sections and tabs when a model property changes
3. Executes dynamic actions on dynamic attributes based on the spring actions attached to the
model
4. Automatically saves input data when the user fills a form from the accelerator
−→ Go to the solution.
Mock 3 - Question 2
When you use advanced personalization what are the valid scopes for segment rule results?
1. Singleton
2. Session
3. Web
4. Permanent
−→ Go to the solution.
Mock 3 - Question 3
Choose the right definition for the modulegen ant task
1. Generate sets of dependent extensions to quickly start new projects or create new applications
2. Generate a single dependent extension to quickly start new projects or create new applications
3. Generate new extensions based on extension templates
4. Generate new empty extensions
−→ Go to the solution.
Mock 3 - Question 4
Which of the following are out of the box point of services ?
1. Factory
2. ServiceDesk
3. Store
4. Warehouse
−→ Go to the solution.
15.1. QUESTIONS
Mock 3 - Question 5
What attribute from the stock level item are mandatory?
1. A product model
2. A product code
3. A point of service
4. A warehouse
−→ Go to the solution.
Mock 3 - Question 6
What is the ant command used to generate a new backoffice extension ?
1. ant modulegen
2. ant ybackofficegen
3. ant extgen
4. ant extensiongen
−→ Go to the solution.
Mock 3 - Question 7
Which of the following language are available to write dynamic form scripts?
1. beanshell
2. groovy
3. spel
4. javascript
−→ Go to the solution.
Mock 3 - Question 8
What is the correct way to create a new cockpit ?
1. add a new line in the xml config file for cockpit (cockpits.xml)
2. create a new cockpit model from the hac (impex) or the hmc
3. generate a new extension from ycockpit
4. run ant cockpitgen
−→ Go to the solution.
273
274
CHAPTER 15. MOCK EXAM 3
Mock 3 - Question 9
Inside the configuration folder you have a file called local_tenant_all.properties, what is it ?
1. a property file for all tenants
2. a property file for the all tenant
3. a property file for the master tenant
4. none of the above
−→ Go to the solution.
Mock 3 - Question 10
Why would you use a widget virtual socket rather than a widget regular socket
1. to add a socket at runtime
2. to connect more than one output or input
3. to to override an existing socket
4. none of the above
−→ Go to the solution.
Mock 3 - Question 11
What statements are true about the widget application context ?
1. it belongs to the CS cockpit
2. it offers auto-reload capabilities
3. it is a child of the web application context
4. none of the above
−→ Go to the solution.
Mock 3 - Question 12
Dynamic forms can perform actions on which of the following elements ?
1. spring bean
2. enumeration
3. backoffice orchestrator
4. none of the above
−→ Go to the solution.
15.1. QUESTIONS
Mock 3 - Question 13
What statements are true about a new extension created from the ycockpit template ?
1. it has only one perspective
2. it has no perspective
3. it creates a new context path based on the name of your extension
4. it creates an admin user to access your cockpit
−→ Go to the solution.
Mock 3 - Question 14
A cockpit perspective is composed of which of the following elements ?
1. a navigation area
2. a browser area
3. an editor area
4. a product area
−→ Go to the solution.
Mock 3 - Question 15
What statement(s) are true about cockpit wizards ?
1. it guides users through complex item creation
2. it is used by the admin user only
3. wizards can be configured with a ZK editor
4. wizards are part of the backoffice framework not the cockpit framework
−→ Go to the solution.
Mock 3 - Question 16
When implementing a new payment provider, what is the most important ?
1. requests should be done using SSL encryption
2. sensitive attribute should be encrypted
3. enforce PCI compliance rules
4. use HOP over SOP
−→ Go to the solution.
275
276
CHAPTER 15. MOCK EXAM 3
Mock 3 - Question 17
What are the new features of Hybris V6 compared to V5?
1. backoffice
2. Yaas integration
3. rule engine
4. smart edit
−→ Go to the solution.
Mock 3 - Question 18
What makes a B2B implementation different than a B2C?
1. B2B needs to manage customer credit
2. B2C needs to integrate customers organization
3. B2B most likely will ask customer to login before they can access the catalog
4. B2B doesn’t integrate payment
−→ Go to the solution.
Mock 3 - Question 19
What is de the default password encryption?
1. none
2. md5
3. sha-512
4. pbkdf2
−→ Go to the solution.
Mock 3 - Question 20
How can you create a new promotion rule?
1. from the backoffice by using a template
2. from the hmc using the appropriate wizard
3. from the backoffice from scratch
4. from ant using the promogen target
−→ Go to the solution.
15.1. QUESTIONS
277
Mock 3 - Question 21
What are OCC v2 new features?
1. stateless
2. stateful
3. restful
4. xml or json response format
−→ Go to the solution.
Mock 3 - Question 22
In SAP Hybris 6.2 what is the recommended to have promotions
1. the promotion engine
2. the promotion module
3. the jalo layer
4. none of the above
−→ Go to the solution.
Mock 3 - Question 23
When 2 promotions (promotion engine) have the same priority how does SAP Hybris order them
1. alphabetically
2. can’t be determined
3. date of creation
4. uuid
−→ Go to the solution.
Mock 3 - Question 24
What statements are true about the rule compiler ?
1. when compiling it uses the IR data structure
2. it is used to transform promotion rules into rules
3. it turns source rules into executables
4. none of the above
−→ Go to the solution.
278
CHAPTER 15. MOCK EXAM 3
Mock 3 - Question 25
How do you define a new RAO object ?
1. create new item type in a items.xml file
2. create new rao type in a items.xml file
3. create new bean in a beans.xml file
4. create new rao in a rao.xml file
−→ Go to the solution.
Mock 3 - Question 26
When creating a new condition translator what are the available conditions ?
1. RuleIrTrueCondition
2. RuleIrFalseCondition
3. RuleIrGroupCondition
4. RuleIrAttributeCondition
−→ Go to the solution.
Mock 3 - Question 27
Where should you manage the visibility restrictions of an existing CMS page ?
1. hac
2. hmc
3. CMS cockpit
4. none of the above
−→ Go to the solution.
Mock 3 - Question 28
What statements are true about flexible search restrictions ?
1. they only apply for anonymous users
2. they never apply for admingroup users
3. you cannot disable restrictions
4. they target one item type
−→ Go to the solution.
15.1. QUESTIONS
279
Mock 3 - Question 29
Tenants let you choose a specific ?
1. set of extensions
2. time zone
3. currency
4. database
−→ Go to the solution.
Mock 3 - Question 30
Can you use SOLR to index something else than products ?
1. yes, if you have at least 2 solr servers
2. yes, if you have at least 2 tenants
3. yes, if you create a new index
4. no, it’s not possible
−→ Go to the solution.
Mock 3 - Question 31
To create a new CMS restriction type (for example loyal customers with at least 3 past orders)
what do you need to do ?
1. create a new item type for your restriction extending AbstractRestriction
2. create an implementation of de.hybris.platform.cms2.servicelayer.services.evaluator.CMSRestrictionEvaluator
with the restriction logic
3. create a new spring bean for my restriction evaluator
4. create a new spring bean to map my evaluator with my item type
−→ Go to the solution.
Mock 3 - Question 32
What could be improved with the following DAO ?
package de.hybris.dao;
import de.hybris.platform.core.model.ItemModel;
import de.hybris.platform.core.model.product.ProductModel;
import de.hybris.platform.servicelayer.internal.dao.DefaultGenericDao;
import java.util.List;
import java.util.Set;
public class MyDao extends DefaultGenericDao<ItemModel> {
280
CHAPTER 15. MOCK EXAM 3
public MyDao(String typecode) {
super(ProductModel._TYPECODE);
}
֒→
public List<ProductModel> searchProduct(String code){
return this.getFlexibleSearchService().<ProductModel>search("select {pk}
from {Product} where id=’"+code+"’").getResult();
}
}
1. use args instead of concatenating the string
2. avoid unused import (java.util.set)
3. extends CachedDao<ProductModel>
4. use a direct SQL query
−→ Go to the solution.
Mock 3 - Question 33
How many item types can a single cache region handle ?
1. only one
2. as many as you need
3. cache regions only cache flexible search queries
4. none of the above
−→ Go to the solution.
Mock 3 - Question 34
Choose the best definition for the FIFO eviction strategy ?
1. objects are evicted based on their age, newest first
2. objects are evicted based on their io use, lowest first
3. objects are evicted based on their size, biggest first
4. none of the above
−→ Go to the solution.
Mock 3 - Question 35
What can you do with the Assised Service Module (ASM) ?
1. create a cart in behalf of a customer
2. create a new product from a responsive storefront
15.1. QUESTIONS
3. manage a customer account from my account section in behalf of a customer
4. assign an anonymous cart to a customer
−→ Go to the solution.
Mock 3 - Question 36
What is best approach to implement the following requirements ?
From my custom backoffice perspective, I want the product description to be
֒→
filled with the product name automatically if empty.
1. create a new prepare interceptor
2. create a new dynamic form for the backoffice
3. customize the ProductModel constructor
4. create a cron job to scan products
−→ Go to the solution.
Mock 3 - Question 37
How does SAP Hybris redirect a URL is redirect to the correct store front ?
1. using different port
2. stores have URL patterns
3. websites have URL patterns
4. using different ips
−→ Go to the solution.
Mock 3 - Question 38
Where can you define a new socket for a widget ?
1. myextension-widgets.xml
2. myextension-backoffice.xml
3. mywidget/definition.xml
4. mywidget/config.xml
−→ Go to the solution.
Mock 3 - Question 39
What functionality should you use to periodically check for product out of stock ?
1. task service
2. cronjob service
3. stockCheck service
4. productSentinel service
−→ Go to the solution.
281
282
CHAPTER 15. MOCK EXAM 3
Mock 3 - Question 40
Can you override a content slot defined in a page template when you are editing a page ?
1. yes, if the slot is empty
2. yes, if you are editing another page template extending the first one
3. yes
4. no, page template slots are meant to be shared across pages
−→ Go to the solution.
Mock 3 - Question 41
What statements are true about macrodefs ?
1. they are part of the build framework
2. they can add build custom logic logic before or after each build step
3. they can be defined in the extensioninfo.xml
4. none of the above
−→ Go to the solution.
Mock 3 - Question 42
What version(s) of OCC is activated by default ?
1. V1
2. V2
3. V1 and V2
4. none
−→ Go to the solution.
Mock 3 - Question 43
When call OCC API, request filters are executed before or after the controllers ?
1. always before
2. always after
3. controllers are responsible for running filters
4. none of the above
−→ Go to the solution.
15.1. QUESTIONS
Mock 3 - Question 44
What statements are true about the following relation definition ?
<relation code="Product2KeywordRelation" autocreate="true" generate="true"
֒→
localized="true">
<deployment table="Prod2KeywordRel" typecode="604"/>
<sourceElement qualifier="keywords" type="Keyword" cardinality="many"
֒→
ordered="true" collectiontype="list">
<description>Keywords</description>
<modifiers read="true" write="true" search="true"
֒→
optional="true"/>
</sourceElement>
<targetElement qualifier="products" type="Product" cardinality="many"
֒→
ordered="false">
<description>Products</description>
<modifiers read="true" write="true" search="true"
֒→
optional="true"/>
</targetElement>
</relation>
1. defines a new item type Product2KeywordRelation
2. will create a new database table Prod2KeywordRel
3. a relation can’t be localized
4. a new attribute products will be visible from the Keyword item type
−→ Go to the solution.
Mock 3 - Question 45
Choose the right definition for a converter ?
1. create new instance of model objects and call populators to populate them
2. create new instance of data objects and call populators to populate them
3. populate a data object attributes from a model object
4. populate a model object attributes from a data object
−→ Go to the solution.
Mock 3 - Question 46
Is this a correct flexible search query ?
delete from {Product} where {code} like ’prd123’
1. no, because it’s missing the semi colon
2. no, because you can’t use like in a where clause
3. no, because flexible search query can’t execute delete statements
4. no, because you need the primary key to delete an item
−→ Go to the solution.
283
284
CHAPTER 15. MOCK EXAM 3
Mock 3 - Question 47
If one item attribute contains sensitive data what should you do ?
1. use password encrypted attribute
2. use xss encoder
3. use secured attribute protection
4. use transparent attribute encryption
−→ Go to the solution.
Mock 3 - Question 48
In a multi tenant system how could you be sure that a Spring bean is unique across different tenants
?
1. use the tenant scope
2. use the default singleton scope
3. use the prototype scope
4. none of the above
−→ Go to the solution.
Mock 3 - Question 49
facets could be of which type ?
1. MultiSelectAnd
2. MultiSelectOr
3. Refine
4. Define
−→ Go to the solution.
Mock 3 - Question 50
Which of the following item types are valid B2B item types ?
1. B2BUnit
2. B2BBudget
3. B2BCostCenter
4. B2BCustomer
−→ Go to the solution.
15.1. QUESTIONS
Mock 3 - Question 51
Give the correct definition of cross site scripting ?
1. malicious code is sent to and executed by end users’ web browsers
2. malicious code is sent to and executed by SAP Hybris
3. malicious code is sent to and executed by the database
4. malicious code is sent to and executed by the JSP page
−→ Go to the solution.
Mock 3 - Question 52
How can you install an SAP license for SAP Hybris ?
1. ant -install /home/hybris/license.txt
2. ant licenceInstall /home/hybris/license.txt
3. ./license.sh -install /home/hybris/license.txt
4. ./licenseInstall.sh /home/hybris/license.txt
−→ Go to the solution.
Mock 3 - Question 53
Why would you run a dependent synchronization ?
1. your catalogs extend each other
2. you want to avoid cross references between catalog versions
3. you want to have cross references between catalog versions
4. none of the above
−→ Go to the solution.
Mock 3 - Question 54
What happen when you update SAP Hybris ?
1. it updates items type code according to items.xml files
2. it imports all impex files
3. it drops database tables if item type are not defined anymore
4. none of the above
−→ Go to the solution.
285
286
CHAPTER 15. MOCK EXAM 3
Mock 3 - Question 55
After adding a new attribute into the product item type definition, what is needed to forward this
attribute into the SOLR index ?
1. nothing the build process would generate a value resolver based on the attribute type and
map it with SOLR
2. you must create a new value resolver
3. you must create a new SolrIndexedProperty item
4. none of the above
−→ Go to the solution.
Mock 3 - Question 56
Which of the following are available accelerators within SAP Hybris 6.2 ?
1. China accelerator
2. B2B accelerator
3. Telco accelerator
4. Travel accelerator
−→ Go to the solution.
Mock 3 - Question 57
What is the best way to start a new project from an accelerator ?
1. ant extgen nameOfTheAccelerator
2. ant modulegen nameOfTheAccelerator
3. ./install.sh -i nameOfTheAccelerator
4. ./install.sh -p nameOfTheAccelerator
−→ Go to the solution.
Mock 3 - Question 58
What steps are required to create a new wizard for a legacy cockpit ?
1. defines a new Spring bean for the wizard de.hybris.platform.cockpit.wizards.Wizard
2. defines a new Spring bean for the wizard configuration de.hybris.platform.cockpit.wizards.generic.CreateWizard
3. create zul files for each wizard’s pages
4. defines a custom WizardPageController
−→ Go to the solution.
15.1. QUESTIONS
287
Mock 3 - Question 59
How should you implement the following requirement ?
We need all products within our SAP Hybris system to carry a new uid generated
֒→
from an external system integrated with our platform.
1. use a classification attribute
2. use a categorization attribute
3. use a product variant attribute
4. none of the above
−→ Go to the solution.
Mock 3 - Question 60
How should you implement the following requirement ?
We need to have a different product catalog for each season. Most important we
֒→
need to be able to work on any catalog at any moment even if they are not
֒→
online.
1. create 4 different product catalogs
2. create 4 different catalog versions
3. create 5 different catalog versions
4. create 4 different stores
−→ Go to the solution.
Mock 3 - Question 61
How should you install a the captcha addon into your store front extension ?
1. ant addoninstall -Daddonnames="captchaaddon" -DaddonStorefront.myStoreFront="myStoreFront"
2. ant addoninstall -Daddonnames="captchaaddon" myStoreFront
3. add <requires-extension name="captchaaddon"/> into your store front extensioninfo.xml
4. add myStoreFront.additionalWebSpringConfigs.captchaaddon=classpath
:/captchaaddon/web/spring/captchaaddon-web-spring.xml into your property file
−→ Go to the solution.
Mock 3 - Question 62
Choose the appropriate term defined by ?
User interface where you can create and maintain rules and rule templates
1. Rule Engine
2. Rule Cockpit
288
CHAPTER 15. MOCK EXAM 3
3. Rule Design
4. Rule Builder
−→ Go to the solution.
Mock 3 - Question 63
How could SAP Hybris decide to create multiple consignments for the same order ?
1. if you have implemented a custom business process for order fulfillment
2. if you have matching order splitting strategy
3. if you use the B2B accelerator
4. whenever size of a product is too big for one shipment
−→ Go to the solution.
Mock 3 - Question 64
Is this a valid impex file ?
INSERT_UPDATE Employee;UID;name;groups(uid);description;password
;CustomerSupportAdministrator;Customer Support
֒→
Administrator;customersupportadministratorgroup;This generic Customer Support
֒→
Administrator.;1234
1. yes
2. no
3. yes, if you use the legacy mode
4. yes, if you add a password encryption [password=md5]
−→ Go to the solution.
Mock 3 - Question 65
How can you be sure your property file are compatible with every existing characters (French,
Chinese, Vietnamese, Hindi...) ?
1. each language should have a different encoding (UTF-FR for French, ISO-HINDI for Indian,...)
2. enforce encoding all your property files in ASCII
3. enforce encoding all your property files in UTF-1
4. none of the above
−→ Go to the solution.
15.1. QUESTIONS
289
Mock 3 - Question 66
What is the correct definition of the service layer ?
1. interconnects data objects with the client (api, controllers...) and hold logic to perform
business processes
2. interconnects external service with SAP Hybris hold logic to perform business processes
3. interconnects model objects with the client (api, controllers...) hold logic to perform business
processes
4. interconnects model objects with the the dao layer
−→ Go to the solution.
Mock 3 - Question 67
What media storage strategy does SAP Hybris 6.2 offers out of the box ?
1. nfs media storage strategy
2. Amazon S3 media storage strategy
3. Google Cloud media storage strategy
4. Windows Azure Blob media storage strategy
−→ Go to the solution.
Mock 3 - Question 68
When creating a new cms component item type what item type should yours extend from ?
1. CMSItem
2. SimpleCMSComponent
3. AbstractCMSComponent
4. CMSComponentType
−→ Go to the solution.
Mock 3 - Question 69
How to you access the backoffice orchestrator ?
1. Login as an admin into the backoffice and open the orchestrator perspective
2. Login as an admin into the hmc and open the orchestrator perspective
3. Login as an admin into the hac and open the orchestrator tab
4. none of the above
−→ Go to the solution.
290
CHAPTER 15. MOCK EXAM 3
Mock 3 - Question 70
In a widget zul file what slot(s) can you use to embed another widget ?
1. <widget .../>
2. <widgetslot .../>
3. <widgetchild .../>
4. <widgetchildren .../>
−→ Go to the solution.
Mock 3 - Question 71
How does SAP Hybris provides to secure the platform ?
1. attribute encryption
2. xss protection
3. access rights
4. password encoding
−→ Go to the solution.
Mock 3 - Question 72
How does SOLR handle localized attributes ?
1. it creates a copy of the each product document for each language
2. it creates a map for each localized attribute (the key being the language code)
3. it creates one attribute for each language (name ends with _en, _de...)
4. it doesn’t store localized attributes
−→ Go to the solution.
Mock 3 - Question 73
When connecting two widgets through a socket, what statements are true ?
1. the data type must be serializable
2. output and input must be compatible (String->String, Integer->Number)
3. output and input must be of the same class
4. you can’t mix virtual and non virtual socket
−→ Go to the solution.
15.1. QUESTIONS
Mock 3 - Question 74
What do you need to provide to create a search restriction ?
1. targeted attribute(s)
2. targeted catalog(s)
3. targeted user or user group
4. targeted tenant
−→ Go to the solution.
Mock 3 - Question 75
Which of the following are price row attributes ?
1. currency
2. price group
3. user price group
4. minimum quantity
−→ Go to the solution.
Mock 3 - Question 76
Which of the following are valid workflow action statuses ?
1. new
2. pending
3. deleted
4. disabled
−→ Go to the solution.
Mock 3 - Question 77
What is the correct definition of a B2B approver ?
1. to provide customer approval for an order
2. to view the reports of the organization’s expenditure
3. to be able to administer the organization structure
4. to be able to place order
−→ Go to the solution.
291
292
CHAPTER 15. MOCK EXAM 3
Mock 3 - Question 78
Is it possible to abort a cron job ?
1. yes, if your job performable extends AbortJobPerformable
2. yes, if isAbortable() returns true
3. yes, if you implement the abortable logic within the PerformResult method of your job
4. none of the above
−→ Go to the solution.
Mock 3 - Question 79
Which of the following user / user group can’t be deleted ?
1. anonymous
2. cockpitgroup
3. backofficegroup
4. anonymousgroup
−→ Go to the solution.
Mock 3 - Question 80
When writing a new integration test class, what already existing class should you extend to assure
isolation ?
1. ServiceLayerIsolatedTest
2. ServiceLayerTest
3. ServiceLayerRollbackTransactionalTest
4. ServiceLayerTransactionalTest
Solutions
Mock 3 - Solution 1
2 are correct.
Dynamic forms are used to add logic within a wizard or editor area.
−→ Go back to the question.
Mock 3 - Solution 2
2 and 4 are correct.
−→ Go back to the question.
Mock 3 - Solution 3
1 is correct.
15.2. SOLUTIONS
−→ Go back to the question.
Mock 3 - Solution 4
3 and 4 are correct.
−→ Go back to the question.
Mock 3 - Solution 5
2 and 4 are correct.
−→ Go back to the question.
Mock 3 - Solution 6
3 is correct.
−→ Go back to the question.
Mock 3 - Solution 7
1,2,3 and 4 are correct.
−→ Go back to the question.
Mock 3 - Solution 8
3 is correct.
−→ Go back to the question.
Mock 3 - Solution 9
2 is correct.
−→ Go back to the question.
Mock 3 - Solution 10
1 is correct.
−→ Go back to the question.
Mock 3 - Solution 11
2 and 3 are correct.
−→ Go back to the question.
Mock 3 - Solution 12
4 is correct.
−→ Go back to the question.
Mock 3 - Solution 13
1 and 3 are correct.
−→ Go back to the question.
Mock 3 - Solution 14
1, 2 and 3 are correct.
−→ Go back to the question.
Mock 3 - Solution 15
1 is correct.
−→ Go back to the question.
Mock 3 - Solution 16
3 is correct.
293
294
−→ Go back to the question.
Mock 3 - Solution 17
1,2,3 and 4 are correct.
−→ Go back to the question.
Mock 3 - Solution 18
1 and 3 are correct.
−→ Go back to the question.
Mock 3 - Solution 19
4 is correct.
−→ Go back to the question.
Mock 3 - Solution 20
1 and 3 are correct.
−→ Go back to the question.
Mock 3 - Solution 21
1 and 3 are correct.
−→ Go back to the question.
Mock 3 - Solution 22
1 is correct.
−→ Go back to the question.
Mock 3 - Solution 23
2 is correct.
−→ Go back to the question.
Mock 3 - Solution 24
1 and 3 are correct.
−→ Go back to the question.
Mock 3 - Solution 25
3 is correct.
−→ Go back to the question.
Mock 3 - Solution 26
1,2,3 and 4 are correct.
−→ Go back to the question.
Mock 3 - Solution 27
3 is correct.
−→ Go back to the question.
Mock 3 - Solution 28
2 and 4 are correct.
−→ Go back to the question.
Mock 3 - Solution 29
1,2,3 and 4 are correct.
CHAPTER 15. MOCK EXAM 3
15.2. SOLUTIONS
−→ Go back to the question.
Mock 3 - Solution 30
3 is correct.
−→ Go back to the question.
Mock 3 - Solution 31
1,2,3 and 4 are correct.
−→ Go back to the question.
Mock 3 - Solution 32
1,2 and 3 are correct.
−→ Go back to the question.
Mock 3 - Solution 33
3 is correct.
−→ Go back to the question.
Mock 3 - Solution 34
4 is correct.
−→ Go back to the question.
Mock 3 - Solution 35
1,3 and 4 are correct.
−→ Go back to the question.
Mock 3 - Solution 36
2 is correct.
−→ Go back to the question.
Mock 3 - Solution 37
2 is correct.
−→ Go back to the question.
Mock 3 - Solution 38
1 and 3 are correct.
−→ Go back to the question.
Mock 3 - Solution 39
2 is correct.
−→ Go back to the question.
Mock 3 - Solution 40
3 is correct.
−→ Go back to the question.
Mock 3 - Solution 41
1 and 2 are correct.
−→ Go back to the question.
Mock 3 - Solution 42
2 is correct.
295
296
CHAPTER 15. MOCK EXAM 3
−→ Go back to the question.
Mock 3 - Solution 43
1 is correct.
−→ Go back to the question.
Mock 3 - Solution 44
2 and 4 are correct.
−→ Go back to the question.
Mock 3 - Solution 45
2 is correct.
−→ Go back to the question.
Mock 3 - Solution 46
3 is correct.
−→ Go back to the question.
Mock 3 - Solution 47
4 is correct.
−→ Go back to the question.
Mock 3 - Solution 48
4 is correct.
Each tenant has its own application context and therefore beans are unique across different tenants.
−→ Go back to the question.
Mock 3 - Solution 49
1,2 and 3 are correct.
−→ Go back to the question.
Mock 3 - Solution 50
1,2,3 and 4 are correct.
−→ Go back to the question.
Mock 3 - Solution 51
1 is correct.
−→ Go back to the question.
Mock 3 - Solution 52
3 is correct.
−→ Go back to the question.
Mock 3 - Solution 53
2 is correct.
−→ Go back to the question.
Mock 3 - Solution 54
4 is correct.
−→ Go back to the question.
Mock 3 - Solution 55
3 is correct.
15.2. SOLUTIONS
297
−→ Go back to the question.
Mock 3 - Solution 56
1,2,3 and 4 are correct.
−→ Go back to the question.
Mock 3 - Solution 57
2 is correct.
−→ Go back to the question.
Mock 3 - Solution 58
1,2 and 3 are correct.
4 is wrong because it’s not required to define a custom WizardPageController, and you can choose
to use the default de.hybris.platform.cockpit.wizards.impl.DefaultPageController
−→ Go back to the question.
Mock 3 - Solution 59
4 is correct.
4 is correct because in this case you should add a new attribute within the Product item type
itself.
−→ Go back to the question.
Mock 3 - Solution 60
3 is correct.
One catalog version for each season plus one Online version.
−→ Go back to the question.
Mock 3 - Solution 61
1 is correct.
−→ Go back to the question.
Mock 3 - Solution 62
4 is correct.
−→ Go back to the question.
Mock 3 - Solution 63
2 is correct.
−→ Go back to the question.
Mock 3 - Solution 64
2 is correct.
When running update you need to have [unique=true] on at least one attribute header.
−→ Go back to the question.
Mock 3 - Solution 65
4 is correct.
By default SAP Hybris use UTF-8 for property files, make sure that every people involve in
translating content use UTF-8.
−→ Go back to the question.
Mock 3 - Solution 66
3 is correct.
298
CHAPTER 15. MOCK EXAM 3
−→ Go back to the question.
Mock 3 - Solution 67
2 and 4 are correct.
−→ Go back to the question.
Mock 3 - Solution 68
2 and 3 are correct.
−→ Go back to the question.
Mock 3 - Solution 69
4 is correct.
You 1 is partially correct, there is no orchestrator perspective instead you simply need to to press
F4.
−→ Go back to the question.
Mock 3 - Solution 70
2 and 4 are correct.
−→ Go back to the question.
Mock 3 - Solution 71
1,2,3 and 4 are correct.
−→ Go back to the question.
Mock 3 - Solution 72
3 is correct.
−→ Go back to the question.
Mock 3 - Solution 73
1 and 2 are correct.
−→ Go back to the question.
Mock 3 - Solution 74
3 is correct.
−→ Go back to the question.
Mock 3 - Solution 75
1,2,3 and 4 are correct.
−→ Go back to the question.
Mock 3 - Solution 76
2 and 4 are correct.
−→ Go back to the question.
Mock 3 - Solution 77
1 is correct.
−→ Go back to the question.
Mock 3 - Solution 78
4 is correct.
In order for your cronjob to be abortable you would need 2 and 3.
You need the job to be aware of the fact that it can abort itself, and you need to implement the
logic to abort it, something like :
15.2. SOLUTIONS
if (clearAbortRequestedIfNeeded(cronJob))
{
return new PerformResult(CronJobResult.ERROR, CronJobStatus.ABORTED);
}
−→ Go back to the question.
Mock 3 - Solution 79
1 is correct.
−→ Go back to the question.
Mock 3 - Solution 80
4 is correct.
299
300
CHAPTER 15. MOCK EXAM 3
Alphabetical Index
OAuth 2, 56
OCC, 53
301
Download