Uploaded by Kali Geosun

Hybris 6.0.0 2-3 - Ambient

advertisement
5/27/2022
Platform
Generated on: 2022-05-27 20:10:51 GMT+0000
SAP Commerce | 6.0.0
PUBLIC
Original content: https://help.sap.com/docs/SAP_COMMERCE/d0224eca81e249cb821f2cdf45a82ace?locale=en-US&state=PRODUCTION&version=6.0.0.0
Warning
This document has been generated from the SAP Help Portal and is an incomplete version of the official SAP product documentation. The information included in custom
documentation may not re ect the arrangement of topics in the SAP Help Portal, and may be missing important aspects and/or correlations to other topics. For this reason,
it is not for productive use.
For more information, please visit the https://help.sap.com/docs/disclaimer.
Clustered Environment
The SAP Commerce Cluster is a number of individual SAP Commerce installations using a common set of data on one database. The cluster functionality offers you a wealth
of con gurable options.
You may need to have several SAP Commerce installations in a cluster environment. You may use standard or advanced SAP Commerce Cluster functionality depending on
whether you want to have complete session failover capabilities. Find more information in the documentation in the table below:
Main Page
Description
Child Pages
This is custom documentation. For more information, please visit the SAP Help Portal
1
5/27/2022
Main Page
Description
Cluster
This document describes the SAP Commerce Cluster
functionality. It gives information about how to set up a SAP
Commerce cluster and describes the con guration settings
needed to tune your cluster system
Child Pages
Cluster FAQ
Clustering
Con guring a SAP Commerce Cluster
Protocols Supported by JGroups
Node-speci c Con gurations
Rolling Update on the Cluster
Semi-Session Failover
Cluster Improvements and ID Autodiscovery
Advanced Clustering
This document introduces the SAP Commerce Advanced
Cluster Module that extends basic SAP Commerce Cluster
functionality with complete session failover capabilities
Transparent HTTP Session Failover
Using Apache Tomcat Session Replication
Using Oracle Coherence with an Extension
Using Apache HTTP Server as Load Balancer
Load Balancer's Example Con guration Inlab Balance
Advanced Clustering
The advanced cluster functionality provides capabilities of SAP Commerce in a cluster extended by complete session failover capabilities with Tomcat based servers or
bundled Oracle coherence. Advanced clustering enables balancing the load between different cluster nodes and HTTP Session replication.
 Note
Before Implementing
A SAP Commerce module may include or enable functionality that is not covered by your individual license. Make sure to limit your implementation to features as de ned
in your license contract. In case of doubt, please contact your SAP Sales representative.
Related Information
SAP Commerce in a Cluster
Transparent HTTP Session Failover
Session failover mechanism prevents HTTP session loss after the node this session was bound to goes down. SAP Commerce includes the so-called transparent HTTP
session failover mechanism.
HTTP is a stateless protocol, that is, the server is unaware whether any requests are related to one another. A common way to allow some sort of session management is by
using session cookies.
However, HTTP sessions are typically bound to one node in a web server cluster. If the node goes down, the HTTP sessions on that node are lost. To avoid HTTP session loss,
the web server cluster needs to have some session failover mechanism. A common session failover mechanism is session replication, which makes sure that HTTP sessions
are replicated across the entire cluster. One typical technical means of such replication is serialization.
SAP Commerce includes a transparent HTTP session failover mechanism.
Transparent means that the functionality is automatic and the application (in this case, SAP Commerce) does not have to handle any of the session management.
HTTP Session Failover means that the HTTP sessions that are assigned to web requests can be replicated onto every individual web server cluster node. By
consequence, even if a web server node goes down, the HTTP sessions can still be recovered and be processed on another web server node.
Note that the transparent HTTP session failover takes place on the web application level only. On the web application level, SAP Commerce uses other modi cations for
sessions than on the ServiceLayer. Therefore, the transparent HTTP session failover is no replacement for the SAP Commerce Cluster. For example, CronJobs do not run on
the web application level and therefore cannot use this transparent HTTP session failover.
How Does Transparent HTTP Session Failover Work?
This is custom documentation. For more information, please visit the SAP Help Portal
2
5/27/2022
Figure: Typical Productive System Infrastructure, reduced to the components that are relevant for transparent HTTP session failover.
The gure shows an excerpt from a typical production system architecture:
1. The client opens a connection to the system such as http://www.myshop.com, thus creating a web request.
2. The load balancer dispatches the web request onto one of the nodes, depending on the load balancing strategy.
3. The transparent HTTP session failover makes sure that the sessions are replicated across the cluster. Session replication is indicated by dotted blue lines in the
gure.
You can set up your system to use either sticky sessions or non-sticky sessions.
Sticky Sessions
Here, all web requests of one HTTP session are served from the same cluster node.
If a request of a HTTP session was rst dispatched to Node 1 such as http://www1.myshop.com, all subsequent requests will be dispatched to Node 1, such as
http://www1.myshop.com.
Non-Sticky Sessions
Here, web requests are dispatched to random nodes across the cluster, depending on the load balancing strategy.
If a request of a HTTP session was rst dispatched to Node 1 such as http://www1.myshop.com, subsequent requests might be dispatched to any nodes, such as
http://www3.myshop.com.
Without a session replication mechanism, you need to use sticky sessions: on a non-sticky session system, every individual node which has processed the session once will
have an individual copy of the session. Take a session cart, for example: on a non-sticky session system, each time the session is processed by a different node, that node
holds a representation of the cart at the time. This might result in 25 different versions of the cart in a 25 node system.
Possible Scenarios of Setup
In SAP Commerce you can use sticky sessions, non-sticky sessions, and transparent HTTP session failover, resulting in three possible scenarios:
Scenario
Description and Recommendation
Sticky sessions without session replication
Consider this scenario if maximum performance is important to you and if you can accept
that sessions are lost if the respective cluster node goes down. If session loss is not
acceptable to you, consider the approaches with session failover.
Sticky sessions, plus transparent HTTP session failover for session replication
Sticky sessions provide better performance over non-sticky sessions.
Non-sticky sessions, plus transparent HTTP session failover for session replication
Not recommended because sticky sessions perform better than Non-Sticky Sessions: the
replication of sessions between nodes takes some time and also costs some performance.
Consider using sticky sessions plus transparent HTTP session failover instead.
Setting Up Transparent HTTP Session Failover
These steps need to be completed only once. As soon as the infrastructure for load balancing and transparent HTTP session failover is set up, you can use the infrastructure
for any number of extensions.
1. Choose and con gure the technology used for session replication. You can use either the Apache Tomcat session replication mechanism or Oracle Coherence.
This is custom documentation. For more information, please visit the SAP Help Portal
3
5/27/2022
The Apache Tomcat is available for free and less complex to set up. Oracle Coherence is better in performance than the Apache Tomcat, but must be licenced and is
more complex to set up.
The Apache Tomcat default session replication mechanism
See Using Apache Tomcat Session Replication.
Oracle Coherence
See Using Oracle Coherence with an Extension.
2. Choose and con gure a load balancer.
You can use any load balancer. Typically, in production environments, a hardware load balancer is used. However, for testing in project use, for example, a hardware
load balancer might be too expensive or not be available. Instead of a hardware load balancer, you can use software load balancers, such as:
Apache http Server.
For details on setup, please refer to Using Apache HTTP Server as Load Balancer.
Inlab Balancer
For details on setup, please refer to Load Balancer's Example Con guration - Inlab Balance.
Related Information
JaloSession
Platform Filters
About Extensions
Semi-Session Failover
Using Apache Tomcat Session Replication
SAP Commerce supports session replication in SAP Commerce Server.
Context
To enable HTTP session replication (transparent HTTP session failover), modify the con guration of the pre-bundled Apache Tomcat. For additional detail, see Tomcat 7.0
Cluster Howto
.
For the Apache Tomcat to use session replication, you need to make some modi cations. These setup steps are required once per Apache Tomcat instance. In the case of
SAP Commerce Server, this means that you need to make these modi cations on every SAP Commerce Server instance.
 Caution
Not all extensions support session replication.
Procedure
1. Put the following Tomcat session replication con guration inside the Engine tag of the <HYBRIS_CONFIG_DIR>/tomcat/conf/server.xml le.
<Engine name="Catalina" defaultHost="localhost">
...
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"
channelSendOptions="8">
<Manager className="org.apache.catalina.ha.session.DeltaManager"
expireSessionsOnShutdown="false"
notifyListenersOnReplication="true"/>
<Channel className="org.apache.catalina.tribes.group.GroupChannel">
<Membership className="org.apache.catalina.tribes.membership.McastService"
address="228.0.0.4"
port="45564"
frequency="500"
dropTime="3000"/>
<Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
address="auto"
port="4000"
autoBind="100"
selectorTimeout="5000"
maxThreads="6"/>
<Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
<Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/>
</Sender>
<Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>
<Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/>
</Channel>
<Valve className="org.apache.catalina.ha.tcp.ReplicationValve" filter=""/>
<Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/>
<ClusterListener className="org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener"/>
<ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
</Cluster>
This is custom documentation. For more information, please visit the SAP Help Portal
4
5/27/2022
Each invocation of ant all replaces the <HYBRIS_BIN_DIR>/platform/tomcat/conf/server.xml le (used by Tomcat) with new one generated from this
template so make any permanent changes in the <HYBRIS_CONFIG_DIR>/tomcat/conf/server.xml le
2. Make sure that the IP address and the port values in the Membership element in the server.xml le are identical for all Apache Tomcat instances. It has to be so
because an Apache Tomcat cluster is identi ed by the combination of an IP address and a port, such as:
<Membership
className="org.apache.catalina.tribes.membership.McastService"
address="228.0.0.4"
port="45564" />
 Note
Under Microsoft Windows, Tomcat clustering doesn't work when cluster nodes are on the same physical machine.
3. Invoke ant all and make sure that the <HYBRIS_BIN_DIR>/platform/tomcat/conf/server.xml le contains cluster con guration from step 1.
4. Con gure Session Manager for all the contexts (extensions) that should have session replication enabled. To do this, replace <Manager pathname="" /> with
<Manager className="org.apache.catalina.ha.session.DeltaManager" expireSessionsOnShutdown="false"
notifyListenersOnReplication="true" /> for chosen extensions in the <HYBRIS_BIN_DIR>/platform/tomcat/conf/server.xml le.
For example, if you wish to enable session replication for storefront (yacceleratorstorefront extension) replace:
<!-- 'yacceleratorstorefront' extension's context for tenant 'master' -->
<Context path="/yacceleratorstorefront" docBase="/Users/i310983/session-replication-test/commerce-suite-5.7.0.0.3241/hybris/bin/e
<Manager pathname="" />
<Loader platformHome="/Users/i310983/projects/dev-platform-core/bin/platform" className="de.hybris.tomcat.HybrisWebappLoader"
</Context>
with
<Context path="/yacceleratorstorefront" docBase="/Users/i310983/session-replication-test/commerce-suite-5.7.0.0.3241/hybris/bin/e
<Manager className="org.apache.catalina.ha.session.DeltaManager" expireSessionsOnShutdown="false" notifyListenersOnReplication
<Loader platformHome="/Users/i310983/projects/dev-platform-core/bin/platform" className="de.hybris.tomcat.HybrisWebappLoader"
</Context>
If this element is not commented out, an exception will occur during start up of the Apache Tomcat which is part of SAP Commerce Server, and the clustering will not
work:
WARNING: Manager [ org.apache.catalina.session.StandardManager@ed5d9d] does not implement ClusterManager, addition to cluster has
 Note
This le can be overwritten by build process, so make sure that you have correct Manager set before starting a cluster node!
5. If you con gured everything properly, check whether you can see org.apache.catalina.tribes logs after startup, for example:
Sep 15, 2015 4:36:11 PM org.apache.catalina.ha.session.DeltaManager startInternal
INFO: Register manager localhost#/yacceleratorstorefront to cluster element Engine with name Catalina
Sep 15, 2015 4:36:11 PM org.apache.catalina.ha.session.DeltaManager startInternal
INFO: Starting clustering manager at localhost#/yacceleratorstorefront
Sep 15, 2015 4:36:11 PM org.apache.catalina.ha.session.DeltaManager getAllClusterSessions
INFO: Manager [localhost#/yacceleratorstorefront], requesting session state from org.apache.catalina.tribes.membership.MemberImpl
Sep 15, 2015 4:36:11 PM org.apache.catalina.ha.session.DeltaManager waitForSendAllSessions
INFO: Manager [localhost#/yacceleratorstorefront]; session state send at 9/15/15 4:36 PM received in 101 ms
6. Test whether session replication works:
a. Log in to yacceleratostorefront on the rst node - you should have two JSESSIONID cookies created.
b. Add some products to the cart.
c. Log in with a different browser that supports cookie manipulation to another node - you should also have two JSESSIONID cookies created.
d. Edit these two JESESSIONID cookies content so that they match the JSESSIONID of the rst node.
e. Refresh the second browser - you should have the same session as on the other node and browser - all the changes you do in one browser will be visible in the
other - this is a proof that session is replicated.
 Note
When testing, pay attention to CartRestorationFilter. It stores additional cookie with a unique id that matches cart id that is stored in database.
When SAP Commerce detects that this cookie exists but there's no session if fetches cart data from database. This can give an impression that session
replication is working when in fact it is not.
Related Information
Running SAP Commerce
https://tomcat.apache.org/tomcat-7.0-doc/cluster-howto.html
Extensions Using Session Replication
Follow these steps to use the transparent HTTP session failover with your custom extension.
Context
These steps are not needed for extensions written by SAP Commerce. If your custom extension doesn't contain a web module, you don't need to follow these steps either.
To con gure an extension to support session failover:
This is custom documentation. For more information, please visit the SAP Help Portal
5
5/27/2022
Procedure
1. Add the <distributable /> directive to your extension's web/webroot/WEB-INF/web.xml le:
<?xml version="1.0" encoding="iso-8859-1"?>
<web-app id="mywebapp">
<distributable/>
2. Set the following property in your local.properties le:
session.replication.support=true;
The property enables the session replication support globally for all extensions. The SessionFilter that needs to be included in your Platform lter chain handles
the session failover.
3. Optional: If you use the deprecated HybrisInitFilter, modify the <filter> section:
Make sure that HybrisInitFilter is enabled.
Add the touch.httpSession init lter parameter inside web/webroot/WEB-INF/web.xml, and set the value to true:
<filter>
<filter-name>InitFilter</filter-name>
<filter-class>de.hybris.platform.util.HybrisInitFilter</filter-class>
<!-- touch httpSession every time jaloSession changes (for session failover) (default = false) -->
<init-param>
<param-name>touch.httpSession</param-name>
<param-value>true</param-value>
</init-param>
[...]
</filter>
Setting touch.httpSession to true allows session replication through serialization of the JaloSession.
 Note
Find Out More
The HttpSession object is modi ed by SAP Commerce by adding an attribute, jalosession. However, session replication systems cannot detect changes in the
JaloSession object assigned to the HttpSession. Therefore, changes in the JaloSession are not replicated onto other web server cluster nodes by factory default.
The touch.httpSession parameter affects the RootRequestFilter and, by consequence, the HybrisInitFilter. If set to true, the parameter causes
the lters to "touch" the HttpSession object by re-setting the same JaloSession to the HttpSession object. This re-setting of the jalosession attribute
causes the HttpSession object to appear modi ed to session replication mechanisms, and the HttpSession object will be replicated. By consequence,
changes in the JaloSession are also replicated. This allows SAP Commerce to use common session replication systems.
web/webroot/WEB-INF/web.xml
<?xml version="1.0" encoding="iso-8859-1"?>
<web-app id="springmvc" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<distributable/>
<display-name>myapp</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
[...]
<filter>
<filter-name>InitFilter</filter-name>
<filter-class>de.hybris.platform.util.HybrisInitFilter</filter-class>
<!-- touch httpSession every time jaloSession changes (for session failover) (default = false) -->
<init-param>
<param-name>touch.httpSession</param-name>
<param-value>true</param-value>
</init-param>
[...]
</filter>
Related Information
Platform Filters
Using Oracle Coherence with an Extension
To use session replication with Oracle Coherence for web applications, all JSP pages and servlets in that web application must be wrapped in Oracle Coherence classes. This
process is automatically done by Coherence*Web Installer.
Setting Up Oracle Coherence for Use with SAP Commerce
This is custom documentation. For more information, please visit the SAP Help Portal
6
5/27/2022
Oracle Coherence is available as a ZIP le for download:
1. Download Oracle Coherence: http://www.oracle.com/technetwork/middleware/coherence/downloads/index.html
2. Extract the ZIP le.
3. Place the coherence directory on the same level as the <${HYBRIS_BIN_DIR}> directory, such as:
Setting Up Your Extensions to Use Oracle Coherence
The upcoming preparatory steps are required for every extension that you write and in which you wish to use transparent HTTP session failover.
For extensions written by SAP, these preparatory steps are not needed. For extensions written by yourself, you need these preparatory steps only if you wish to use the
transparent HTTP session failover. If your extension does not contain a web module, you do not need these preparatory steps.
Setting Up the Web Module of Your Extensions
To con gure an extension to support session failover, you need to modify the extension's web/webroot/WEB-INF/web.xml le:
1. Add the <distributable/> directive, such as:
web/webroot/WEB-INF/web.xml
<?xml version="1.0" encoding="iso-8859-1"?>
<web-app id="mywebapp">
<distributable/>
2. Set the following property in your local.properties le:
session.replication.support=true;
This enables the session replication support globally for all extensions. The SessionFilter that needs to be included in your Commerce Platform. Filters chain
handles the session failover. For more details read hybris Platform Filters.
If you are still using the deprecated HybrisInitFilter modify the <filter> section by:
Making sure that the HybrisInitFilter is enabled.
Adding the touch.httpSession init lter parameter, and setting the value to true.
web/webroot/WEB-INF/web.xml
<filter>
<filter-name>InitFilter</filter-name>
<filter-class>de.hybris.platform.util.HybrisInitFilter</filter-class>
<!-- touch httpSession every time jaloSession changes (for session failover) (default = false) -->
<init-param>
<param-name>touch.httpSession</param-name>
<param-value>true</param-value>
</init-param>
[...]
</filter>
Setting this parameter to true allows session replication via serialization of the JaloSession.
 Note
Find Out More
The HttpSession object is modi ed by SAP Commerce by adding an attribute, jalosession. However, session replication systems cannot detect changes
in the JaloSession object assigned to the HttpSession. Therefore, changes in the JaloSession are not replicated onto other web server cluster nodes by
factory default.
The touch.httpSession parameter affects the RootRequestFilter and, by consequence, the HybrisInitFilter. If set to true, the parameter
causes the lters to "touch" the HttpSession object by re-setting the same JaloSession to the HttpSession object. This re-setting of the jalosession
attribute causes the HttpSession object to appear modi ed to session replication mechanisms, and the HttpSession object will be replicated. By
consequence, changes in the JaloSession are also replicated. This allows SAP Commerce to use common session replication systems.
web/webroot/WEB-INF/web.xml
<?xml version="1.0" encoding="iso-8859-1"?>
<web-app id="springmvc" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
This is custom documentation. For more information, please visit the SAP Help Portal
7
5/27/2022
<distributable/>
<display-name>myapp</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
[...]
<filter>
<filter-name>InitFilter</filter-name>
<filter-class>de.hybris.platform.util.HybrisInitFilter</filter-class>
<!-- touch httpSession every time jaloSession changes (for session failover) (default = false) -->
<init-param>
<param-name>touch.httpSession</param-name>
<param-value>true</param-value>
</init-param>
[...]
</filter>
Modifying the Build Framework for Your Extensions
To make use of Oracle Session Replication, an extension has to be wrapped by Oracle Coherence. You can make SAP Commerce do this wrapping automatically by hooking
into the SAP Commerce Build Framework.
This example assumes that the extension which is wrapped by Oracle Coherence is named extensionName. Please replace extensionName with your actual extension's
name.
Add the following code to the buildcallbacks.xml le in the <${HYBRIS_BIN_DIR}>/extensionName directory. This code implements a new Apache Ant build
target: buildCoherence:
<property name="coherence.dir" location="${HYBRIS_BIN_DIR}/../coherence" />
<import file="${coherence.dir}/ant-coherence-web-handling.xml" />
<target name="buildCoherence">
<!-- create war at temp folder -->
<!-- MODIFICATION: you have to replace 'extensionName.war' by the real one-->
<echo>Creating war file at ${HYBRIS_TEMP_DIR}/coherence_war/extensionName.war</echo>
<!-- MODIFICATION: you have to replace 'extensionName' by the real one-->
<buildwar destdir="coherence_war" extname="extensionName" />
<!-- apply Coherence installation -->
<!-- MODIFICATION: you have to replace 'extensionName.war' by the real one-->
<echo>Installing Coherence on ${HYBRIS_TEMP_DIR}/coherence_war/extensionName.war
to ${HYBRIS_TEMP_DIR}/coherence_war/coherence_temp/extensionName.war</echo>
<!-- MODIFICATION: you have to replace 'extensionName' by the real one-->
<coherence-install
dir="${HYBRIS_TEMP_DIR}/coherence_war"
coherence.dir="${coherence.dir}"
app.name="extensionName" />
<!-- delete web folder at target extension -->
<!-- MODIFICATION: you have to replace 'extensionName' by the real one-->
<echo>Deleting web folder of target extension extensionName</echo>
<!-- MODIFICATION: you have to replace 'ext.extensionName.path' by the real one-->
<delete dir="${ext.extensionName.path}/web/webroot" />
<!--
and unzip modified war to it -->
<!-- MODIFICATION: you have to replace 'extensionName' by the real one-->
<echo>Unzipping Coherence war to web folder of target extension extensionName</echo>
<!-- MODIFICATION: you have to replace 'extensionName.war' by the real one-->
<unzip
dest="${ext.extensionName.path}/web/webroot"
src="${HYBRIS_TEMP_DIR}/coherence_war/coherence_temp/extensionName.war" />
</target>
Building Extensions Using Oracle Coherence
1. Call ant buildCoherence in the ${HYBRIS_BIN_DIR}/platform directory to wrap the extensionName extension with Oracle Coherence.
2. Wait for the build to complete.
 Note
Calling ant clean requires calling ant buildCoherence.
The wrapper process of Oracle Coherence patches the les which are compiled by the SAP Commerce Build Framework. During ant clean, the compiled les are
removed. By consequence, the wrapper les for Oracle Coherence are removed, too. Therefore, to make sure that the wrapper les are available, you need to call
ant buildCoherence after every call ofant clean.
3. Start SAP Commerce Server:
Normal operation mode:
This is custom documentation. For more information, please visit the SAP Help Portal
8
5/27/2022
a. Navigate to the <${HYBRIS_BIN_DIR}>/platform directory.
b. To start the SAP Commerce Server:
On Windows systems call the hybrisserver.bat le.
On Unix systems call the hybrisserver.sh le, such as: ./hybrisserver.sh
Debug operation mode, requiring develop con guration template:
a. Navigate to the <${HYBRIS_BIN_DIR}>/platform directory.
b. To start the SAP Commerce Server:
On Windows systems run the hybrisserver.bat le with the debug parameter, such as hybrisserver.bat debug.
On Unix systems call the hybrisserver.sh le with the debug parameter, such as ./hybrisserver.sh debug.
For more information, see Con guration Templates.
 Note
If you got this line in console during the start
INFO
| jvm 1
| main
| 2009/10/29 15:33:25.449 | 2009-10-29 15:33:25.199/54.703 Oracle Coherence 3.4.2/411 <D5> (thread
a. Rename WEB-INF/classes/coherence-override-local.xml to tangosol-coherence-override.xml.
b. Rebuild SAP Commerce.
4. There are two ways of verifying whether Oracle Coherence has been set up correctly:
You can check the log whether a second node is started and has noti ed that there is already Oracle Coherence cluster and it is has been attached to it:
INFO [Coherence] 2009-10-30 09:45:24.280/99.687 Oracle Coherence EE 3.4.2/411 <
Info> (thread=Cluster, member=n/a): This Member(Id=3, Timestamp=2009-10-30 09:45
:23.85, Address=192.168.146.15:8089, MachineId=64015, Location=site:Local-Deskto
p,machine:testmachine1,process:3228, Edition=Enterprise Edition, Mode=Development,
CpuCount=2, SocketCount=2) joined cluster "Local-Dev" with senior Member(Id=1,
Timestamp=2009-10-29 16:33:33.933, Address=192.168.146.160:8088, MachineId=64160
, Location=site:Local-Desktop,machine:testmachine2,process:1148, Edition=Enterpr
ise Edition, Mode=Development, CpuCount=4, SocketCount=4)
Or you can verify the correct setup of Oracle Coherence via JMX.
Test Scenarios
Setup
Two SAP Commerce Cluster nodes (using different ports) and InLab Balance as Loadblanacer running on the same machine (Mac OS-X).
Testing
1. Only one node should be running
2. Enter the store ( http://localhost:8080/springmvcstore/, 8080 is the con gured loadbalancer port here)
3. Login as user demo (password 1234)
4. Fill the cart
5. Start the second node
6. If the 2nd node is up and running, shutdown the node, which was running at 1st.
7. Verify the cart (cart enties have to be the same)
8. Additionally you can verify if Coherence sends the session to the other node in a serialized way, such as:
INFO [Coherence] 2009-10-30 09:53:24.645/580.052 Oracle Coherence EE 3.4.2/411
<Info> (thread=DistributedCache:DistributedSessions, member=3): Restored from backup 85 partitions
Using Apache HTTP Server as Load Balancer
The Apache HTTP Server is a commonly used, open source http server and is available for many common operating systems. The Apache HTTP Server can be extended in
functionality by integrating modules. By using certain modules, the Apache HTTP Server can be used as a software load balancer, for example.
The Apache HTTP Server can by extended to integrate additional functionality by using modules (also called "mods"). The Transparent HTTP Session Failover functionality
relies on these mods:
1. mod_proxy_balancer
Required. Provides load balancing functionality. For details, see the Apache website: http://httpd.apache.org/docs/2.2/mod/mod_proxy_balancer.html
.
2. mod_headers
Optional. Required for sticky sessions. For details, see the Apache website: http://httpd.apache.org/docs/2.2/mod/mod_headers.html
.
To use such mods, two steps are necessary:
This is custom documentation. For more information, please visit the SAP Help Portal
9
5/27/2022
1. The mods must be made available to the Apache HTTP Server.
2. The Apache HTTP Server must be con gured to use the mods.
Making Mods Available to the Apache HTTP Server
There are two ways of how the Apache HTTP Server can integrate mods:
Standalone.
Modules are compiled independently of the Apache HTTP Server executable. In this case, you can disable unused mods to increase performance.
This is recommended if you use the Apache HTTP Server both as a web server and as a load balancer.
To enable standalone mods, you need to modify the ${APACHE_INSTALL}/conf/httpd.conf le and uncomment the lines that reference mods. For example,
from
${APACHE_INSTALL}/conf/httpd.conf (mods disabled)
#LoadModule
#LoadModule
#LoadModule
#LoadModule
#LoadModule
headers_module modules/mod_headers.so
proxy_module modules/mod_proxy.so
proxy_balancer_module modules/mod_proxy_balancer.so
proxy_connect_module modules/mod_proxy_connect.so
proxy_http_module modules/mod_proxy_http.so
to ${APACHE_INSTALL}/conf/httpd.conf (mods enabled)
LoadModule
LoadModule
LoadModule
LoadModule
LoadModule
headers_module modules/mod_headers.so
proxy_module modules/mod_proxy.so
proxy_balancer_module modules/mod_proxy_balancer.so
proxy_connect_module modules/mod_proxy_connect.so
proxy_http_module modules/mod_proxy_http.so
Built-In
Modules are compiled into the Apache HTTP Server executable. In this case all modules are compiled and loaded every time the Apache HTTP Server is started.
This is recommended if you use the Apache HTTP Server only as a load balancer and not as a web server as well.
Con guring Apache HTTP Server
Once you have set up the Apache HTTP Server as a load balancer, you need to con gure the load balancing:
Sample con guration with sticky sessions: Example Con guration with Sticky Sessions
Sample con guration without sticky sessions: Example Con guration Without Sticky Sessions
Example Con guration with Sticky Sessions
This document provides a load balancer example con guration for Inlab Balance.
Let's imagine that we want to setup our environment in a following manner:
We want application to be accessible by 192.168.0.1 IP address on port 80
We want application to run on two cluster nodes:
First on port 8001 and with 192.168.0.2 IP address
Second on port 9001 and with 192.168.0.3 IP address
Apache HTTP Server's Con guration
Apache HTTP Server can be con gured using httpd.conf le.
Append the following code sample to the existing HTTP Server's con guration le:
${APACHE_INSTALL}/conf/httpd.conf
Listen 80
Header add Set-Cookie: "ROUTEID=.%{BALANCER_WORKER_ROUTE}e; path=/" env=BALANCER_ROUTE_CHANGED
<Proxy balancer://mycluster>
BalancerMember http://192.168.0.2:8001 route=node1
BalancerMember http://192.168.0.3:9001 route=node2
</Proxy>
ProxyPass / balancer://mycluster/ stickysession=ROUTEID
ProxyPassReverse / balancer://mycluster/
<Location /balancer-manager>
SetHandler balancer-manager
This is custom documentation. For more information, please visit the SAP Help Portal
10
5/27/2022
Order Deny,Allow
Deny from all
Allow from all
</Location>
Thanks to this line:
${APACHE_INSTALL}/conf/httpd.conf
ProxyPass /myapp balancer://mycluster/myapp stickysession=ROUTEID
it is completely transparent to user which cluster's member he is connected to (address bar always shows url of load balancer server, not cluster's members url)
Load balancer port is set to 80 and application is visible as http://192.168.0.1:80/myapp
Example Con guration Without Sticky Sessions
This document provides a load balancer example con guration without sticky sessions.
Let's imagine that we want to set up our environment in the following manner:
We want application to be accessible by 192.168.0.1 IP address on port 80
We want application to run on two cluster nodes:
First on port 8001 and with 192.168.0.2 IP address
Second on port 9001 and with 192.168.0.3 IP address
Apache HTTP Server's Con guration
Apache HTTP Server can be con gured using httpd.conf le.
Append the following code sample to the existing HTTP Server's con guration le:
${APACHE_INSTALL}/conf/httpd.conf
Listen 80
<Proxy balancer://mycluster>
BalancerMember http://192.168.0.2:8001/ loadfactor=2
BalancerMember http://192.168.0.3:9001/ loadfactor=1
</Proxy>
ProxyPass /myapp balancer://mycluster/myapp
ProxyPassReverse /myapp balancer://mycluster/myapp
<Location /balancer-manager>
SetHandler balancer-manager
Order Deny,Allow
Deny from all
Allow from all
</Location>
In provided example ratio is 2:1 and sticky sessions are off, so every third request goes to 192.168.0.3:9001
Thanks to this line:
${APACHE_INSTALL}/conf/httpd.conf
ProxyPass /myapp balancer://mycluster/myapp
it is completely transparent to user which cluster's member he is connected to (address bar always shows url of load balancer server, not cluster's members url)
Load balancer port is set to 80 and application is visible as http://192.168.0.1:80/myapp
Load Balancer's Example Con guration - Inlab Balance
This document includes a load balancer example con guration for Inlab Balance.
Let's imagine that we want to setup our environment in a following manner:
We want application to be accessible by 192.168.0.1 IP address on port 80
We want application to run on two cluster nodes:
First on port 8001 and with 192.168.0.2 IP address
Second on port 9001 and with 192.168.0.3 IP address
This is custom documentation. For more information, please visit the SAP Help Portal
11
5/27/2022
Inlab Balance Con guration
Balance can be con gured by passing command line parameters.
balance 80 -H -b 192.168.0.1 192.168.0.2:8001 192.168.0.3:9001 %
parameter
description
80
port used to access Inlab Balance
H
failover to next host even if sticky sessions are on
b 192.168.0.1
IP addres used to access Inlab Balance
192.168.0.2:8001
IP address and port of the rst node
192.168.0.3:9001
IP address and port of the second node
%
turns on sticky sessions mode
For more details please consult Inlab Balance documentation on the Inlab website.
Mac OS-X related modi cations
Make le
# $Id: Makefile,v 1.45 2008/04/08 17:39:08 tommy Exp $
#CFLAGS=-g -I.
CFLAGS=-O2 -Wall -Wstrict-prototypes -Wuninitialized
# uncomment for any OS other than Cygwin
BALANCE=balance
ROOT=root
INSTALL=install
BINDIR=/sbin
MANDIR=/opt/local/share/man/man1
#
#
#
#
uncomment for Solaris
LIBRARIES=-lsocket -lnsl
INSTALL=/usr/ucb/install
BINDIR=/usr/local/libexec
#
#
#
#
uncomment for Cygwin
LIBRARIES=-L/usr/local/lib -lcygipc
BALANCE=balance.exe
ROOT=Administrators
CC=gcc
RELEASE=3.42
all: balance
balance: balance.o butils.o
$(CC) $(CFLAGS) -I. -o balance balance.o butils.o $(LIBRARIES)
balance.o: balance.c balance.h
$(CC) $(CFLAGS) -I. -c balance.c
butils.o: butils.c balance.h
$(CC) $(CFLAGS) -I. -c butils.c
balance.pdf: balance.ps
ps2pdf balance.ps balance.pdf
balance.ps: balance.1
troff -Tpost -man balance.1 | /usr/lib/lp/postscript/dpost > balance.ps
# groff -f H -man balance.1 > balance.ps
ci:
ci -l *.c *.h Makefile balance.1 README balance.spec
clean:
rm -f $(BALANCE) *.o balance.ps balance.pdf
install:
$(INSTALL) -o $(ROOT) -g admin -m 755 $(BALANCE) \
$(DESTDIR)$(BINDIR)/$(BALANCE)
$(INSTALL) -o $(ROOT) -g admin -m 755 balance.1 \
$(DESTDIR)$(MANDIR)
mkdir -p $(DESTDIR)/var/run/balance
chmod 1777 $(DESTDIR)/var/run/balance
release: balance.pdf
rm -rf ./releases/balance-$(RELEASE)
mkdir ./releases/balance-$(RELEASE)
cp balance.1 balance.pdf balance.c balance.h butils.c COPYING Makefile README ./releases/balance-$(RELEASE)
cp balance.spec ./releases/balance-$(RELEASE)/balance.spec
cd releases; tar -cvf balance-$(RELEASE).tar ./balance-$(RELEASE)
cd releases; gzip balance-$(RELEASE).tar
This is custom documentation. For more information, please visit the SAP Help Portal
12
5/27/2022
rpm:
ever
cp releases/balance-$(RELEASE).tar.gz /usr/src/redhat/SOURCES/
rpmbuild -ba balance.spec
cp /usr/src/redhat/SRPMS/balance-$(RELEASE)-1.src.rpm ./releases
cp /usr/src/redhat/RPMS/i386/balance-$(RELEASE)-1.i386.rpm ./releases
ever:
Sample: Connections to the local port 8080 are forwarded alternating to 192.168.146.7:9001 and 192.168.146.7:9004
sudo /sbin/balance -f 8080 192.168.146.7:9001 % 192.168.146.7:9004 %
 Note
The parameter % allows connecting one client always to the same server, for example balancing http sessions to a single server.
Cluster
The SAP Commerce Cluster is a number of individual SAP Commerce installations using a common set of data on one database. A cluster con guration lets you balance the
load between the nodes to scale SAP Commerce in a way that is transparent to the user.
The cluster functionality offers a wealth of con gurable options such as:
Choice of the communication protocol (UDP: both multicast or unicast, or JGroups)
Node-speci c runtime con gurations
Cron jobs for speci c nodes
Session failover
Advanced logging and debug modes
Encryption capability
The SAP Commerce Cluster Module also enables you to run SAP Commerce inside a Cloud environment.
Read Con guring a SAP Commerce Cluster document for a detailed instruction about con guring SAP Commerce in a cluster environment.
Introduction to SAP Commerce Cluster
In a cluster, the individual SAP Commerce is referred to as a node. Each node uses an individual SAP Commerce instance running in an individual JVM.
 Note
It is worth noting that running SAP Commerce in cluster mode is not the same as running it in a multi-tenant mode. The SAP Commerce Cluster is a number of individual,
separate SAP Commerce instances sharing one single set of data, whereas the multi-tenant SAP Commerce is one single SAP Commerce using separate sets of data.
For a discussion of running SAP Commerce in multi-tenant mode, refer to Multi-Tenant Systems.
For a general discussion of caching in the clustered SAP Commerce, see Cache in Platform.
Figure: All nodes within a cluster use the same database.
Cache Invalidation Concept
The core of a SAP Commerce Cluster is a network communication system that makes sure the cache of each individual cluster member only holds valid data. The nodes in
the SAP Commerce Cluster communicate using TCP (JGroups) or UDP, by sending signals to other nodes that mark some cache entries as invalid because a database item
This is custom documentation. For more information, please visit the SAP Help Portal
13
5/27/2022
has been changed. The following is the overview of the cache invalidation process:
1. A description of a product has changed. Therefore, all cache entries referring to the product are invalid.
2. A cluster node where the modi cation has been done sends a noti cation to all cluster nodes that all cache entries holding the product are invalid.
3. Nodes that hold the product in their cache discard the cached data of the product and re-retrieve the product from the database the next time the product is used.
For more information, see:
Cache in Platform
Semi-Session Failover
Main Features
The SAP Commerce Cluster Module offers an array of features to ensure high availability of your implementation, while preserving transparency to the end user.
Choice of UDP Multicast, UDP Unicast, or JGroups as Communication Protocols
Consult your network administrator to choose the right protocol for your deployment.
There are pros and cons to each solution. Generally, JGroups provides the fastest communication and can be used both in the cloud for testing purposes and in a LAN or
WAN network. UDP Multicast has some limitations in that some routers do not allow multicast network traffic by default. Amazon Elastic Compute Cloud (Amazon EC2) does
not work using UDP, either. For more details, see Transport Layer Concepts.
Load Balancing
To balance the load between two cluster nodes means that user requests are balanced between all of the nodes, instead of being sent to only one server.
If you need redundancy, use a hardware load balancer or a software load balancer. Read our Third-Party Compatibility document for possible options on what kind of load
balancers can be used with SAP Commerce. How to use and set up a load balancer is beyond the scope of this document but for more information about load balancing, see
Advanced Clustering.
 Tip
In some con gurations, you might want to use two nodes but without load balancing. For example, let's say you have one machine that is a cluster node for your front-end
system, and another machine for the Hybris Management Console. They both are part of a cluster, which means they do not display invalid data, and you can access them
directly by the IP address or hostname.
Semi-Session Failover
Sessions used by clients that are bound to an individual cluster node, stick with the cluster node. Therefore, the SAP Commerce Cluster uses so-called sticky sessions. In
addition, SAP Commerce offers a semi-session failover mechanism. Session failover is a mechanism to transfer an existing session to a different cluster node than the one
where the session is assigned. This is useful if the cluster node where the session was originally assigned goes offline due to planned maintenance or due to a hardware
defect, for example. Without a session failover mechanism, all the data kept with the sessions on the offline cluster node is lost. For more details, see Semi-Session Failover.
Node-Speci c Runtime Con gurations
Nodes in a cluster may have different memory capacity or varying CPU performance. Using node-speci c cluster settings enables the specifying of a custom con guration for
each individual node, such as having varying cache size, or having different folder paths for media read or replication folders. For more details, see Node-speci c
Con gurations.
Performance Optimizations
It is possible to tweak Windows settings to improve the performance of the SAP Commerce Cluster by modifying:
Datagram size
Thread scheduling
For more details see the SAP Commerce Cluster Performance Tips section in Tips on Performance Tuning.
Encryption Con guration
To guarantee data integrity, you have to be sure that every node is using the same encryption key. A general default key is part of the release and is stored at
${HYBRIS_BIN_DIR} /platform/ext/core/resources/security/default-128-bit-aes-key.hybris. However, we strongly recommend that you replace this
weak and unsecure key le with your own key, which has to be placed in the ${HYBRIS_CONFIG_DIR} /security directory. For more details, see Transparent Attribute
Encryption (TAE).
This is custom documentation. For more information, please visit the SAP Help Portal
14
5/27/2022
Related Information
Cache in Platform
Transactions
http://www.onjava.com/pub/a/onjava/2001/09/26/load.html
Advanced Clustering
Cluster FAQ
Setting up SAP Commerce in a cluster is not difficult, but there are many variables, and every installation is different. Answers to questions posed by others are available
here to help you.
What About 3rd Party Application Server Clustering Functionality? Do I Have to Enable It?
SAP Commerce clustering is completely independent of application server clustering. You do not need it to ensure the data integrity of your cache. We recommend disabling
all application server clustering systems.
HTTP session failover is also independent of the SAP Commerce cache. However, if you need session failover, then it might be necessary to use the application server session
clustering.
Is the Cluster Transactional?
Yes. Clustering is not a matter of transactions. What we assure is the correct invalidation and isolation of our cache when using transactions.
For more details, see Transactions, and the appropriate sections in Cache in Platform.
Can I Use a Cluster with Nodes on Different Hardware, Operating Systems, or Application Servers?
Short answer: Yes, however, SAP Commerce does not recommend that you do that.
Long answer: The SAP Commerce Clustering feature is not bound to speci c application servers, operating systems, or physical hardware infrastructure.
If your deployment meets the requirements (can send and receive UDP multicast packets), you can set up a cluster with completely mixed components. However, SAP
Commerce does not recommend such a setup for production environments. It is very hard to balance load between different servers, troubleshooting is more complicated,
and the overall setup requires broad knowledge.
Clustering
With SAP Commerce clustering you can run SAP Commerce inside a cloud environment such as Amazon EC2.
Clustering can be based on the JGroups protocol or UDP. Extended capabilities such as balancing the load between different cluster nodes or HTTP Session replication can
be added by using the Advanced Cluster Module.
 Note
Before Implementing
A SAP Commerce module may include or enable functionality that is not covered by your individual license. Make sure to limit your implementation to features as de ned
in your license contract. In case of doubt, please contact your SAP Commerce Sales representative.
Related Information
Advanced Cluster Module
Con guring a SAP Commerce Cluster
Follow the steps to con gure a SAP Commerce cluster.
Context
You can choose between three main protocols:
JGroups
UDP Multicast
UDP Unicast
To set up a cluster, con gure each node individually by editing the local.properties le located in the config folder.
Procedure
1. Modify local.properties to activate the cluster mode:
This is custom documentation. For more information, please visit the SAP Help Portal
15
5/27/2022
clustermode=true #the same for all nodes
2. Modify local.properties to de ne a unique id for the node:
cluster.id=0
#This needs to be unique for each node
3. Modify local.properties to specify the communication protocol. You can choose between JGroups (UDP or TCP), UDP multicast and UDP Unicast:
cluster.broadcast.methods=jgroups #the same for all nodes; Within Jgroups you can select between udp (default) communicatio
cluster.broadcast.methods=udp
#the same for all nodes;
udp Multicast
4. Add protocol-speci c settings depending on your choice of communication protocol. For more information, see JGroups Settings and UDP Cluster Settings.
5. Test the connection between cluster nodes:
a. Go to SAP Commerce Administration Console to make sure that the nodes can see each other. Select the Monitoring tab, Cluster to see a list of available
nodes.
b. Make a change in HMC on node#1 and make sure you can see the change in HMC on node#2
Related Information
Con guring the Behavior of SAP Commerce
JavaDocs and API Documentation
Transport Layer Concepts
JGroups Settings
See the information about JGroups features and settings.
JGroups:
Is a Java toolkit for reliable multicast communication.
Can be used to create groups of processes whose members can send messages to each other.
Saves development time
has a exible protocol stack so an application can be deployed in different environments without having to change code.
Main features of JGroups:
Membership
Transport protocols: UDP (IP Multicast), TCP, JMS
Fragmentation of large messages
Reliable unicast and multicast message transmission. Lost messages are retransmitted.
Failure detection: crashed members are excluded from the membership
Ordering protocols: Atomic (all-or-none message delivery), Fifo, Causal, Total Order (sequencer or token based)
Encryption
Much faster message transmission than with UDP or TCP only
JGroups used in the Commerce Platform comes with two precon gured setups - the rst one using TCP and the second one using UDP as the transport protocol.
JGroups is much faster than using 'pure' UDP or TCP: in our local testing JGroups UDP cluster, sending 10 mln messages took 2 minutes as compared with 3 minutes with
UDP Multicast. Cloud testing yielded similar speed improvement.
JGroups-based Cluster Implementation
Add the following properties to your local.properties le:
 Note
TCP properties included in this example are only valid for TCP con guration. They are ignored for UDP con guration.
local.properties
cluster.broadcast.method.jgroups=de.hybris.platform.cluster.jgroups.JGroupsBroadcastMethod
cluster.broadcast.method.jgroups.tcp.bind_addr=12.34.56.78
cluster.broadcast.method.jgroups.tcp.bind_port=7800
cluster.broadcast.method.jgroups.channel.name=hybris-broadcast
cluster.broadcast.method.jgroups.configuration=jgroups-udp.xml
cluster.broadcast.method.jgroups.configuration property speci es the path to an xml le with the con guration settings. The defaulf con guration for
JGroups is UDP.
If you want to use the TCP con guration instead, change the jgroups.con guration property to
This is custom documentation. For more information, please visit the SAP Help Portal
16
5/27/2022
jgroups-tcp.xml
If you want to use a custom con guration, specify your custom.xml le for UDP, and custom-jgroups-tcp.xml under your extension/resources/jgroups/, add
in local.properties, and restart the server:
local.properties
cluster.broadcast.method.jgroups.configuration=custom.xml or custom-jgroups-tcp.xml
JGroups UDP
Jgroups UDP clustering uses IP multicast for sending messages to all members of a group and UDP datagrams for unicast messages (sent to a single member). When
started, it opens a unicast and multicast socket: the unicast socket is used to send/receive unicast messages, whereas the multicast socket sends/receives multicast
messages. The channel's address will be the address and port number of the unicast socket.
A protocol stack with UDP as transport protocol is typically used with groups whose members run on the same host or are distributed across a LAN. Before running such a
stack a programmer has to ensure that IP multicast is enabled across subnets. It is often the case that IP multicast is not enabled across subnets. In such cases, the stack
has to either use UDP without IP multicasting or other transports such as TCP.
udp.xml JGroups UDP Con guration File
JGroups UDP con guration le
<!-Default stack using IP multicasting. It is similar to the "udp"
stack in stacks.xml, but doesn't use streaming state transfer and flushing
-->
<config xmlns="urn:org:jgroups"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:org:jgroups http://www.jgroups.org/schema/JGroups-3.1.xsd">
<UDP
mcast_port="${hybris.jgroups.mcast_port}"
tos="8"
ucast_recv_buf_size="20M"
ucast_send_buf_size="640K"
mcast_recv_buf_size="25M"
mcast_send_buf_size="640K"
loopback="true"
max_bundle_size="64K"
max_bundle_timeout="30"
ip_ttl="${jgroups.udp.ip_ttl:8}"
enable_bundling="true"
enable_diagnostics="true"
thread_naming_pattern="cl"
timer_type="old"
timer.min_threads="4"
timer.max_threads="10"
timer.keep_alive_time="3000"
timer.queue_max_size="500"
thread_pool.enabled="true"
thread_pool.min_threads="2"
thread_pool.max_threads="8"
thread_pool.keep_alive_time="5000"
thread_pool.queue_enabled="true"
thread_pool.queue_max_size="10000"
thread_pool.rejection_policy="discard"
oob_thread_pool.enabled="true"
oob_thread_pool.min_threads="1"
oob_thread_pool.max_threads="8"
oob_thread_pool.keep_alive_time="5000"
oob_thread_pool.queue_enabled="false"
oob_thread_pool.queue_max_size="100"
oob_thread_pool.rejection_policy="Run"/>
<PING timeout="2000"
num_initial_members="20"/>
<MERGE2 max_interval="30000"
min_interval="10000"/>
<FD_SOCK/>
<FD_ALL/>
<VERIFY_SUSPECT timeout="1500" />
<BARRIER />
<pbcast.NAKACK2 xmit_interval="1000"
xmit_table_num_rows="100"
xmit_table_msgs_per_row="2000"
xmit_table_max_compaction_time="30000"
max_msg_batch_size="500"
use_mcast_xmit="false"
discard_delivered_msgs="true"/>
<UNICAST xmit_interval="2000"
xmit_table_num_rows="100"
xmit_table_msgs_per_row="2000"
xmit_table_max_compaction_time="60000"
conn_expiry_timeout="60000"
max_msg_batch_size="500"/>
<pbcast.STABLE stability_delay="1000" desired_avg_gossip="50000"
max_bytes="4M"/>
This is custom documentation. For more information, please visit the SAP Help Portal
17
5/27/2022
<pbcast.GMS print_local_addr="true" join_timeout="3000"
view_bundling="true"/>
<UFC max_credits="2M"
min_threshold="0.4"/>
<MFC max_credits="2M"
min_threshold="0.4"/>
<FRAG2 frag_size="60K" />
<RSVP resend_interval="2000" timeout="10000"/>
<pbcast.STATE_TRANSFER />
<!-- pbcast.FLUSH /-->
</config>
For full information on JGroup protocols, see Protocols Supported by JGroups.
JGroups TCP Con guration - tcp.xml JGroups TCP Con guration File
Specifying TCP in your protocol stack tells JGroups to use TCP to send messages between group members. Instead of using a multicast bus, the group members create a
mesh of TCP connections.
tcp.xml JGroups TCP Con guration File
<!-- TCP based stack, with flow control and message bundling. This is usually used when IP multicasting cannot be used in a network,
e.g. because it is disabled (routers discard multicast). -->
<config xmlns="urn:org:jgroups" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:org:jgroups http://www.j
<TCP loopback="true"
recv_buf_size="${tcp.recv_buf_size:20M}"
send_buf_size="${tcp.send_buf_size:640K}"
discard_incompatible_packets="true"
max_bundle_size="64K"
max_bundle_timeout="30"
enable_bundling="true"
use_send_queues="true"
sock_conn_timeout="300"
timer_type="new"
timer.min_threads="4"
timer.max_threads="10"
timer.keep_alive_time="3000"
timer.queue_max_size="500"
thread_pool.enabled="true"
thread_pool.min_threads="1"
thread_pool.max_threads="10"
thread_pool.keep_alive_time="5000"
thread_pool.queue_enabled="false"
thread_pool.queue_max_size="100"
thread_pool.rejection_policy="discard"
oob_thread_pool.enabled="true"
oob_thread_pool.min_threads="1"
oob_thread_pool.max_threads="8"
oob_thread_pool.keep_alive_time="5000"
oob_thread_pool.queue_enabled="false"
oob_thread_pool.queue_max_size="100"
oob_thread_pool.rejection_policy="discard"
bind_addr="${hybris.jgroups.bind_addr}"
bind_port="${hybris.jgroups.bind_port}" />
<JDBC_PING connection_driver="${hybris.database.driver}"
connection_password="${hybris.database.password}"
connection_username="${hybris.database.user}"
connection_url="${hybris.database.url}"
initialize_sql="${hybris.jgroups.schema}"/>
<MERGE2 min_interval="10000" max_interval="30000" />
<FD_SOCK />
<FD timeout="3000" max_tries="3" />
<VERIFY_SUSPECT timeout="1500" />
<BARRIER />
<pbcast.NAKACK use_mcast_xmit="true" exponential_backoff="500" discard_delivered_msgs="true" />
<UNICAST />
<pbcast.STABLE stability_delay="1000" desired_avg_gossip="50000" max_bytes="4M" />
<pbcast.GMS print_local_addr="true" join_timeout="3000" view_bundling="true" />
<UFC max_credits="2M" min_threshold="0.4" />
<MFC max_credits="2M" min_threshold="0.4" />
<FRAG2 frag_size="60K" />
<pbcast.STATE_TRANSFER />
</config>
UDP Cluster Settings
See the information about both UDP multicast and UDP unicast implementations.
UDP Multicast Implementation
The UDP-based cluster implementation uses cache invalidation signals sent to all other nodes of the SAP Commerce Cluster using multicast. If a SAP Commerce item is
modi ed on one of the nodes, the node sends a UDP multicast datagram to all other nodes informing them that the cached information on the item is invalid.
Figure: Connection Schema of a UDP-based SAP Commerce Cluster
This is custom documentation. For more information, please visit the SAP Help Portal
18
5/27/2022
Figure: Communication Schema of a UDP-based SAP Commerce Cluster
Con guring a UDP Multicast Based Cluster
When UDP is chosen as the communication protocol, the following settings have to be con gured:
Multicast address, on which the node listens for cluster messages:
local.properties
cluster.broadcast.method.udp.multicastaddress=230.0.0.1
#this ip should be the same for all nodes,
Port on which the node listens for cluster messages:
local.properties
cluster.broadcast.method.udp.port=9997
#the same for all nodes
If you have many enabled network interfaces, specify the address of the interface used for communication:
local.properties
cluster.broadcast.method.udp.networkinterface=<logical_name_of_your_network_interface>
#use the logical interface name, e.g. eth
 Note
If you're getting error bad argument for IP_MULTICAST_IF2, replace the address for the property cluster.broadcast.method.udp.networkinterface with a logical
interface name, for example eth4. To get names for your interfaces, use this code:
import
import
import
import
java.io.*;
java.net.*;
java.util.*;
static java.lang.System.out;
public class ListNIFs
{
public static void main(String args[]) throws SocketException {
Enumeration<NetworkInterface> nets = NetworkInterface.getNetworkInterfaces();
for (NetworkInterface netIf : Collections.list(nets)) {
out.printf("Display name: %s\n", netIf.getDisplayName());
out.printf("Name: %s\n", netIf.getName());
displaySubInterfaces(netIf);
out.printf("\n");
}
}
static void displaySubInterfaces(NetworkInterface netIf) throws SocketException {
Enumeration<NetworkInterface> subIfs = netIf.getSubInterfaces();
for (NetworkInterface subIf : Collections.list(subIfs)) {
out.printf("\tSub Interface Display name: %s\n", subIf.getDisplayName());
out.printf("\tSub Interface Name: %s\n", subIf.getName());
}
}
}
This is custom documentation. For more information, please visit the SAP Help Portal
19
5/27/2022
 Note
Sometimes multicast traffic choses to use IPV6 network interfaces even if we speci cally bind by an IPV4 address. To make sure the JVM uses ipv4 add the following
settings to your tomcat general options in local.properties:
tomcat.generaloptions=….. -Djava.net.preferIPv4Stack=true -Djava.net.preferIPv4Addresses=true
Testing the Cluster
Testing is done with UDP Multicast broadcast packets. To test the con gurations, use the
ant udpsniff
de ned in the build.xml le in the ${HYBRIS_BIN_DIR} /resources/ant directory . Remember to use this speci c category for running
ant udpsniff
.
ant udpsniff
listens to the con gured port for invalidations and prints them to the console.
Run the following command on one of the other cluster nodes:
c:\data\hybris\bin\platform\resources\ant\> ant udpsniff
...
[java] INFO [DefaultBroadcastService] updating cluster island ID -1->15488775967864160
[java] INFO [UDPSniffer] UDP Multicast Receiver (udpsniff) configured with the following parameter:
[java] INFO [UDPSniffer] Interface: /0.0.0.0, NetworkInterface: null
[java] INFO [UDPSniffer] Receiving packets from group /230.0.0.1
[java] INFO [UDPSniffer] /192.168.146.107:[?://?|ver:4010100|15488775967864160-7665975202688-58|1|1of1 (content: 80 bytes)]
[java] INFO [UDPSniffer] /192.168.146.107:[?://?|ver:4010100|15488775967864160-7665975202688-59|1|1of1 (content: 80 bytes)]
[java] INFO [UDPSniffer] /192.168.146.107:[?://?|ver:4010100|15488775967864160-7665975202688-60|1|1of1 (content: 80 bytes)]
[java] INFO [UDPSniffer] /192.168.146.107:[?://?|ver:4010100|15488775967864160-7665975202688-61|1|1of1 (content: 80 bytes)]
[java] INFO [UDPSniffer] /192.168.146.107:[?://?|ver:4010100|15488775967864160-7665975202688-62|99|1of1 (content: 6 bytes)]
[java] INFO [UDPSniffer] /192.168.146.107:[?://?|ver:4010100|15488775967864160-7665975202688-63|99|1of1 (content: 28 bytes)]
[java] INFO [UDPSniffer] /192.168.146.107:[?://?|ver:4010100|15488775967864160-25258161494096-48|1|1of1 (content: 80 bytes)]
[java] INFO [UDPSniffer] /192.168.146.107:[?://?|ver:4010100|15488775967864160-25258161494096-49|1|1of1 (content: 80 bytes)]
If you receive these messages, the UDP multicast connection between these nodes is correctly con gured. The UDP Sniffer uses the master tenant data, therefore only UDP
messages from own cluster will display.
Running the SAP Commerce Server
If you have successfully tested the clustering, you can start the application server on each cluster node.
You will receive output that looks like this:
D:\data\platform>hybrisserver.bat
[...]
INFO [Http11Protocol] Initializing Coyote HTTP/1.1 on http-9001
INFO [Http11Protocol] Initializing Coyote HTTP/1.1 on http-9002
[...]
INFO [hybrisserver] *******************************************
INFO [hybrisserver]
INFO [hybrisserver] Starting up hybris Server 4.0.1.0...
INFO [hybrisserver]
INFO [hybrisserver] Configuration:
INFO [hybrisserver]
INFO [hybrisserver] Cluster: 0 (master)
[...]
INFO [Catalina] Server startup in 12265 ms
You can see that the cluster.id is set to 0.
Troubleshooting
Double check that you have the same con guration for cluster.port and cluster.multicastaddress on both machines.
If no packets are received, for testing purposes start the UDP sniffer on the same machine on which the pings are generated. Use another command prompt window
to do this.
If you do not get any output from using
ant udpsniff
, try to run this command with root privileges (on linux machines), change the log level of the rootlogger to debug. Bear in mind that this will result in massive
amounts of log output, so use it only in a testing environment and only for testing purposes.
This is custom documentation. For more information, please visit the SAP Help Portal
20
5/27/2022
If you receive packets on the local machine but not on the remote one, it is possible that they are sent out using wrong network interfaces. You can change the
network interface by con guring cluster.interface.
Check the default time-to-live (TTL) value of the packets
The Commerce Platform does not specify a TTL and so uses the default value of the operating system. If this is set to 0, UDP packages are only processed on the local
machine and are not sent to the network. TTL = 1 means that UDP packages are forwarded only in the LAN.
Make sure that your network interface card fully supports multicasts, both sending and receiving
Make sure that there is no IPv4/IPv6 issue. Try deactivating IPv6 or pinnning the tomcat process to use a speci c IP stack version
local.properties
tomcat.javaoptions=-Djava.net.preferIPv4Stack=true -Djava.net.preferIPv6Addresses=false
If you have set up the cluster correctly and started each instance but the cache invalidation still won't work, you can enable logging of the UDP packets. Add the
following line to your local.properties le:
local.properties
log4j.logger.de.hybris.platform.cache.udp=debug
and restart the SAP Commerce Server.
UDP Unicast - Based Cluster Implementation
As an alternative to JGroups, it is also possible to use UDP Unicast only to send invalidation messages.
Figure: Unicast Traffic
Con guring UDP Unicast
Add the following con guration to the local.properties le:
local.properties
# define server host name or ip ( use a public ip here)
cluster.broadcast.method.unicast.serveraddress=myHostName
# define the server port
cluster.broadcast.method.unicast.port=myPort
# define all known nodes as hostnameOrIp:port
cluster.broadcast.method.unicast.clusternodes=node1HostName:node1Port ; node2HostName:node2Port ; node3HostName:node3Port
# if the interval value is higher than 0 , the platform synchronizes its list of known nodes with all the cluster members, negative va
cluster.broadcast.method.unicast.sync.nodes.interval=-1
 Note
The ping message handler now starts immediately on master tenant startup and it is no longer necessary for the user to go to SAP Commerce Administration Console
for the service to start silently.
If more detailed logging is necessary, add the following con guration to the local.properties le.
local.properties
log4j.logger.de.hybris.platform.cluster.PingBroadcastHandler=DEBUG
log4j.logger.de.hybris.platform.cluster.udp.UnicastBroadcastMethod=DEBUG
Protocols Supported by JGroups
This document describes protocols of JGroup API.
This is custom documentation. For more information, please visit the SAP Help Portal
21
5/27/2022
Transport Layer Protocols
See the con guration options for TCP and UDP protocols.
TCP Con guration Options
Option
Description
bind_addr
The bind address which should be used by this transport.
bind_port
The port to which the transport binds. Default of 0 binds to any (ephemeral) port.
discard_incompatible_packets
Discard packets with a different version if true. Default is false
enable_bundling
Enable bundling of smaller messages into bigger ones. Default is true.
loopback
Messages to self are looped back immediately if true.
max_bundle_size
Maximum number of bytes for messages to be queued until they are sent.
max_bundle_timeout
Max number of milliseconds until queued messages are sent.
oob_thread_pool.keep_alive_time
Timeout in ms to remove idle threads from the OOB pool.
oob_thread_pool.max_threads
Max thread pool size for the OOB thread pool.
oob_thread_pool.min_threads
Minimum thread pool size for the OOB thread pool.
oob_thread_pool_enabled
Switch for enabling thread pool for OOB messages. Default=true.
oob_thread_pool_queue_enabled
Use queue to enqueue incoming OOB messages.
oob_thread_pool_queue_max_size
Maximum queue size for incoming OOB messages. Default is 500.
oob_thread_pool_rejection_policy
Thread rejection policy. Possible values are Abort, Discard, DiscardOldest and Run. Default
is Discard.
recv_buf_size
Receiver buffer size in bytes.
send_buf_size
Send buffer size in bytes.
sock_conn_timeout
Max time allowed for a socket creation in ConnectionTable.
thread_pool.keep_alive_time
Timeout in milliseconds to remove idle thread from regular pool.
thread_pool.max_threads
Maximum thread pool size for the regular thread pool.
thread_pool.min_threads
Minimum thread pool size for the regular thread pool.
thread_pool_enabled
Switch for enabling thread pool for regular messages. Default true.
thread_pool_queue_enabled
Use queue to enqueue incoming regular messages. Default is true.
thread_pool_queue_max_size
Maximum queue size for incoming OOB messages. Default is 500.
thread_pool_rejection_policy
Thread rejection policy. Possible values are Abort, Discard, DiscardOldest and Run. Default
is Discard.
UDP Con guration Options
Option
Description
mcast_port
The multicast port used for sending and receiving packets. Default is 7600.
tos
Traffic class for sending unicast and multicast datagrams. Default is 8.
ucast_recv_buf_size
Receive buffer size of the unicast datagram socket. Default is 64'000 bytes.
ucast_send_buf_size
Send buffer size of the unicast datagram socket. Default is 100'000 bytes.
mcast_recv_buf_size
Receive buffer size of the multicast datagram socket. Default is 500'000 bytes.
mcast_send_buf_size
Send buffer size of the multicast datagram socket. Default is 100'000 bytes.
loopback
Messages to self are looped back immediately if true.
max_bundle_size
Maximum number of bytes for messages to be queued until they are sent.
max_bundle_timeout
Max number of milliseconds until queued messages are sent.
ip_ttl
The time-to-live (TTL) for multicast datagram packets. Default is 8.
enable_bundling
Enable bundling of smaller messages into bigger ones. Default is true.
enable_diagnostics
Switch to enable diagnostic probing. Default is true.
thread_naming_pattern
Thread naming pattern for threads in this channel. Default is cl.
This is custom documentation. For more information, please visit the SAP Help Portal
22
5/27/2022
Option
Description
timer_type
Type of timer to be used. Valid values are "old" (DefaultTimeScheduler, used up to 2.10),
"new" (TimeScheduler2) and "wheel". Note that this property might disappear in future
releases, if one of the 3 timers is chosen as default timer.
timer.keep_alive_time
Timeout in ms to remove idle threads from the timer pool.
timer.max_threads
Max thread pool size for the timer thread pool.
timer.min_threads
Minimum thread pool size for the timer thread pool.
timer_queue_max_size
Max number of elements on a timer queue.
thread_pool.keep_alive_time
Timeout in milliseconds to remove idle thread from regular pool.
thread_pool.max_threads
Maximum thread pool size for the regular thread pool.
thread_pool.min_threads
thread_pool_enabled
Switch for enabling thread pool for regular messages. Default is true.Minimum thread pool
size for the regular thread pool.
thread_pool_queue_enabled
Use queue to enqueue incoming regular messages. Default is true.
thread_pool_queue_max_size
Maximum queue size for incoming OOB messages. Default is 500.
thread_pool_rejection_policy
Thread rejection policy. Possible values are Abort, Discard, DiscardOldest and Run. Default
is Discard.
oob_thread_pool.keep_alive_time
Timeout in ms to remove idle threads from the OOB pool.
oob_thread_pool.max_threads
Max thread pool size for the OOB thread pool.
oob_thread_pool.min_threads
Minimum thread pool size for the OOB thread pool.
oob_thread_pool_enabled
MinSwitch for enabling thread pool for OOB messages. Default is true.
oob_thread_pool_queue_enabled
Use queue to enqueue incoming OOB messages.
oob_thread_pool_queue_max_size
Maximum queue size for incoming OOB messages. Default is 500.
oob_thread_pool_rejection_policy
Thread rejection policy. Possible values are Abort, Discard, DiscardOldest and Run. Default
is Discard.
Discovery Protocols
See the con guration options for the TCPPING and PING protocols.
TCPPING
The TCPPING protocol layer retrieves the initial membership in answer to the GMS's FIND_INITIAL_MBRS event. The initial membership is retrieved by directly contacting
other group members, sending Messages containing point-to-point membership requests. The responses should allow us to determine the coordinator whom we have to
contact in case we want to join the group. When we are a server (after having received the BECOME_SERVER event), we'll respond to TCPPING requests with a TCPPING
response. The FIND_INITIAL_MBRS event will eventually be answered with a FIND_INITIAL_MBRS_OK event up the stack.
Option
Description
initial_hosts
Comma delimited list of hosts to be contacted for initial membership.
num_initial_members
Minimum number of initial members to get a response from. Default is 2.
port_range
Number of ports to be probed for initial membership. Default is 1.
timeout
Timeout to wait for the initial members. Default is 3000 msec.
PING
Initial (dirty) discovery of members. Used to detect the coordinator (oldest member), either by mcasting PING requests to an IP MCAST address or connecting to a
GossipRouter.
Each member responds with a packet {C, A}, where C=coordinator's address and A=own address. After milliseconds or replies, the joiner determines the coordinator from
the responses, and sends a JOIN request to it (handled by GMS). If nobody responds, we assume we are the rst member of a group.
Unlike TCPPING, PING employs dynamic discovery, meaning that the member does not have to know in advance where other group memebers are.
Option
Description
num_initial_members
Minimum number of initial members to get a response from. Default is 2.
timeout
Timeout to wait for the initial members. Default is 3000 msec.
This is custom documentation. For more information, please visit the SAP Help Portal
23
5/27/2022
Merge Protocol Merge2
See the con guration options for the Merge Protocol Merge2 protocol.
If a group gets split for some reasons (e.g. network partition), this protocol merges the subgroups back into one group. It is only run by the coordinator (the oldest member
in a cluster), and periodically multicasts its presence. If another coordinator (for the same group) receives this message, it will initiate a merge process. Note that this
merges subgroups {A,B} and {C,D,E} back into {A,B,C,D,E}, but it does not merge state. The app has to handle the callback to merge state.
Option
Description
max_interval
Maximum time in ms between runs to discover other clusters.
min_interval
Minimum time in msbetween runs to discover other clusters.
Failure Detection Protocols
See the con guration options for FD_SOCK, FD, FD_ALL, and VERIFY_SUSPECT protocols.
FD_SOCK Protocol
Failure detection protocol based on a ring of TCP sockets created between group members. Each member in a group connects to its neighbor (last member connects to rst)
thus forming a ring. Member B is suspected when its neighbor A detects abnormally closed TCP socket (presumably due to a node B crash). However, if a member B is about
to leave gracefully, it lets its neighbor A know, so that it does not become suspected.
One FD_SOCK disadvantage is that hung servers and/or crashed switches will not cause sockets to be closed. Therefore hung members will not be suspected and network
partitions due to switch failures will not be detected. A solution to this problem is to use both FD and FD_SOCK failure detection protocols. For more details refer to Failure
Detection
FD_SOCK uses JGroups defaults
FD Protocol
Failure detection based on heartbeat messages. A member sends 'are-you-alive' messages with a periodicity of 'timeout' milliseconds. After the rst missing heartbeat
response, the initiating member send more 'max_tries' heartbeat messages and the target member is declared suspect only after all heartbeat messages go unanswered.
In the worst case, when the target member dies immediately after answering a heartbeat, the failure takes timeout + timeout + max_tries * timeout = (max_tries + 2) *
timeout milliseconds to detect.
Once a member is declared suspected it will be excluded by GMS. SUSPECT event handling is also subject to interaction with VERIFY_SUSPECT. If we use FD_SOCK instead,
then we don't send heartbeats, but establish TCP sockets and declare a member dead only when a socket is closed.
Option
Description
max_tries
Number of times to send an are-you-alive message.
timeout
Timeout to suspect a node P if neither a heartbeat nor data were received from P. Default is
3000 msec.
FD_ALL Protocol
Failure detection based on simple heartbeat protocol. Every member periodically multicasts a heartbeat. Every member also maintains a table of all members (minus itself).
When data or a heartbeat from P are received, we reset the timestamp for P to the current time. Periodically, we check for expired members, and suspect those.
FD_ALL uses JGroups defaults
VERIFY_SUSPECT Protocol
Veri es that a suspected member is really dead by pinging that member once again. Drops suspect message if member does respond. Tries to minimize false suspicions.
The protocol works as follows: it catches SUSPECT events traveling up the stack. Veri es that the suspected member is really dead. If yes, passes SUSPECT event up the
stack, otherwise discards it. Has to be placed somewhere above the FD layer and below the GMS layer (receiver of the SUSPECT event). Note that SUSPECT events may be
reordered by this protocol.
Option
Description
timeout
Number of millisecs to wait for a response from a suspected member.
Synchronization Protocol BARRIER
See the con guration options for the BARRIER protocol.
This is custom documentation. For more information, please visit the SAP Help Portal
24
5/27/2022
The BARRIER protocol can be used to suspend the delivery of messages up the protocol stack. It can be seen as a distributed counterpart to the barrier notion found in
thread programming. See the con guration options for Protocol BARRIER. All messages up the stack have to go through a barrier. By default, the barrier is open.
When a CLOSE_BARRIER event is received, we close the barrier. This succeeds when all previous messages have completed. Thus, when the barrier is closed, we know that
there are no pending messages processed.
When an OPEN_BARRIER event is received, we simply open the barrier again and let all messages pass in the up direction.
Option
Description
max_close_time
How long can a barrier stay closed (0 means forever).
Reliable Message Transmission Protocols
See the con guration options of the pbcast.NAKACK, pbcast.STABLE, and UNICAST protocols.
pbcast.NAKACK
Lossless and FIFO delivery of multicast messages, using negative acks. E.g. when receiving P:1, P:3, P:4, a receiver asks P for retransmission of message 2.
Option
Description
use_mcast_xmit
Retransmit messages using multicast rather than unicast.
exponential_backoff
The rst value (in milliseconds) to use in the exponential backoff. Enabled if greater than 0.
Default is 0.
discard_delivered_msgs
Should messages delivered to application be discarded.
pbcast.STABLE
Garbage collects messages that have been seen by all members of a cluster. Each member has to store all messages because it may be asked to retransmit. Only when we
are sure that all members have seen a message can it be removed from the retransmission buffers. STABLE periodically gossips its highest and lowest messages seen. The
lowest value is used to compute the min (all lowest seqnos for all members), and messages with a seqno below that min can safely be discarded.
Note that STABLE can also be con gured to run when N bytes have been received (size-based gossipping). This is recommended when sending messages at a high rate,
because time based gossiping might accumulate messages faster than STABLE can garbage collect them.
Option
Description
desired_avg_gossip
Average time to send a STABLE message. Default is 20000 msec.
stability_delay
Delay before stability message is sent. Default is 6000 msec.
max_bytes
Maximum number of bytes received in all messages before sending a STABLE message is
triggered. Default is 0 (disabled)
UNICAST
Lossless and FIFO delivery of unicast messages.
UNICAST for TCP protocol uses JGroups defaults.
UNICAST for UDP protocol uses following options:
Option
Description
xmit_table_max_compaction_time
Number of milliseconds after which the matrix in the retransmission table is compacted
(only for experts).
xmit_table_msgs_per_row
Number of elements of a row of the matrix in the retransmission table (only for experts). The
capacity of the matrix is xmit_table_num_rows * xmit_table_msgs_per_row.
xmit_table_num_rows
Number of rows of the matrix in the retransmission table (only for experts).
max_msg_batch_size
Max number of messages to be removed from a NakReceiverWindow. This property might
get removed anytime, so don't use it !
Group Membership Protocol pbcast.GMS
See the con guration options for the pbcast.GMS protocol.
This is custom documentation. For more information, please visit the SAP Help Portal
25
5/27/2022
Group Membership Service. Responsible for joining/leaving members. Also handles suspected members, and excludes them from the membership. Sends Views (topology
con guration) to all members when a membership change has occurred.
Option
Description
print_local_addr
Print local address of this member after connect. Default is true.
join_timeout
Join timeout. Default is 5000 msec.
view_bundling
View bundling toggle.
Fragmentation Protocol FRAG2
See the con guration options for the FRAG2 protocol.
Fragments messages larger than 'frag_size' bytes. Unfragments at the receiver's side. Works for both unicast and multicast messages.
Compared to FRAG, this protocol does not need to serialize the message in order to break it into smaller fragments: it looks only at the message's buffer, which is a byte
array anyway. We assume that the size addition for headers and src and dest address is minimal when the transport nally has to serialize the message, so we add a
constant (by default 200 bytes). Because of the efficiency gained by not having to serialize the message just to determine its size, FRAG2 is generally recommended over
FRAG.
Option
Description
frag_size
The max number of bytes in a message. Larger messages will be fragmented. Default is
8192 bytes.
State Transfer Protocols
See the con guration options of the pbcast.STATE_TRANSFER, and RSVP protocols.
pbcast.STATE_TRANSFER
Allows a joining member to retrieve a shared group state from the oldest member (coordinator). Other members do not have to stop sending messages, while state transfer
is in progress.
pbcast.STATE_TRANSFER uses JGroups defaults
RSVP Protocol
Protocol which implements synchronous messages. A send of a message M with ag RSVP set will block until all non-faulty recipients (one for unicasts, N for multicasts)
have acked M, or until a timeout kicks in.
Related Information
Cluster - Technical Guide
Node-speci c Con gurations
Using node-speci c cluster settings allows specifying a custom con guration for each individual node, for example varying cache size.
Within an SAP Commerce cluster, it may be necessary to set up individual con guration parameters for each node. It may happen because nodes may have, for example,
different memory capacity or varying CPU performance.
 Note
If you want to use this feature, you still need a local.properties le on each cluster node with a proper con guration described in Con guring a SAP Commerce
Cluster.
A cluster node-speci c property setting is pre xed by cluster. cluster_number, such as:
cluster.12.myproperty=myvalue
cluster.13.myproperty=myvalue2
A node-speci c property applies to a cluster node if cluster_number matches the cluster node number. The code snippet above de nes different values of the myproperty
property for the nodes 12 and 13. By consequence, myproperty has a different value for both nodes, although it is de ned under the same name.
During a SAP Commerce build, only the build framework-related properties are effective. Cluster-node-speci c property values do not apply. This means that you cannot
specify node-speci c build framework properties, such as a ctitious cluster.1.build.compiler=classic. The property would use during the SAP Commerce build the classic
compiler setting for node 1 only.
This is custom documentation. For more information, please visit the SAP Help Portal
26
5/27/2022
The side effect is that you cannot con gure the Apache Tomcat start-up settings via node-speci c property values. The build framework of SAP Commerce writes the startup values for the Apache Tomcat as part of the deploy build target. The build framework cannot write node-speci c startup settings for the Apache Tomcat, because it does
not evaluate node-speci c property values: the node-speci c property values would have to be available at compile time, but are not available until runtime. If you need to
specify node-speci c startup parameters for the Apache Tomcat, you should use the -D command line switch or edit the Apache Tomcat con guration les manually.
Cluster node 15 is a special case. It is used for SAP Commerce when started in stand-alone operation mode, for example when launched from Eclipse and during JUnit tests.
When launched in stand-alone mode, SAP Commerce ignores the value of the cluster. clusternode property.
If no speci c value for cluster.id is de ned in local.properties le, the default value for the cluster.id is set to 15. Cluster node 15 also represents an SAP Commerce
installation in stand-alone mode of operation. In other words, all property values speci c for the cluster node 15 also apply to:
SAP Commerce launched in stand-alone mode
Every instance of SAP Commerce with no value set for the cluster.id property
Region Cache is the default cache. You can con gure the following properties in your local.properties le:
Property Name
Default Property Value
Description
cluster.15.regioncache.entityregion.size
100000
The size of a region that stores all other, non-typesystem
and non-query objects.
cluster.15.regioncache.querycacheregion.size
20000
The size of a region that stores query results.
Customizing Con guration of Read Directories
To con gure read directories separately for each node, use the following code:
media.read.dir=C:\\images
cluster.1.media.read.dir=C:\\data
cluster.2.media.read.dir=D:\\images\\data
#the default for all clusternodes
#if running on node 1, use this
#and this for node 2
 Note
It is good practice to use identical physical machines with the same OS and directory structure to make system maintenance easier.
Customizing Con guration of Media Replication Directories
Commerce Platform has a property media.replication.dirs, which accepts a number of directories to which media instances are written. It can be set at
local.properties or project.properties le.
The following code snippet shows a sample setting of media replication directories. Remember to use double backslashes when specifying the paths.
local.properties
...
media.replication.dirs=C:\\media;N:\\remotedir\\media
In this example, C:\media is a directory at a local hard disk and N:\remotedir\media represents a directory on a remote server. Whenever a media is created, it is written to
any path given here.
In the same way as with the media.read.dir, it is possible to con gure media replication directories speci c to each node in a SAP Commerce cluster.
You can modify the properties for cluster nodes according to the following regular expression:
HybrisConfig.java
^(standalone\\.)?(cluster\\.(\\d+)\\.)?(.*)$
Hence, it is possible to have the property
cluster.1.media.replication.dirs
in the local.properties le for cluster node 1.
 Note
It is not enough to have the whole con guration in one le. Settings for cluster node 1 need to be con gured in local.properties le of node 1 and settings for cluster node
2 need to be con gured in its own local.properties le.
The following gure illustrates two SAP Commerce nodes with different media replication directories. SAP Commerce application server 1 writes the media les to M:\data
and N:\data directories and SAP Commerce application server 2 writes the media les to N:\data and O:\data directories.
In order to con gure cluster nodes for media replication as in the gure above, you need to have the following settings in the local.properties les.
This is custom documentation. For more information, please visit the SAP Help Portal
27
5/27/2022
For SAP Commerce node 1, edit its local.properties at ${HYBRIS_DIR} /config
local.properties
...
cluster.id=1
...
cluster.1.media.replication.dirs=M:\\data;N:\\data
For SAP Commerce node 2, edit its local.properties at ${HYBRIS_DIR} /config
local.properties
...
cluster.id=2
...
cluster.2.media.replication.dirs=N:\\data;O:\\data
Setting the Node ID for an Existing Cron Job
When creating a cron job, you need to set the ID of the node on which the cron job is expected to run. However, the nodeID attribute is an initial attribute and cannot be
altered by the Hybris Management Console once the cron job has been created. For more information, refer to items.xml.
The following code snippet shows how to move a cron job to another cluster node after the cron job has been created:
import
import
import
import
de.hybris.platform.servicelayer.cronjob.CronJobService;
de.hybris.platform.servicelayer.model.ModelService;
de.hybris.platform.cronjob.model.JobModel;
de.hybris.platform.cronjob.model.CronJobModel;
//cronJobService, modelService should be injected here
JobModel jobModel = cronJobService.getJob("helloWorldJobPerformable");
print(cronJobService);
print(jobModel.getJobCronJobs());
for(CronJobModel cronJob : jobModel.getJobCronJobs())
/{
print(cronJob.getCode());
cronJob.setNodeID(Integer.valueOf(10));
modelService.save(cronJob);
}
Rolling Update on the Cluster
The rolling update feature gives you the possibility to update a SAP Commerce cluster without shutting it down.
 Caution
To perform a rolling update, your SAP Commerce database must be version 5.3 or higher. It is not possible to use the type system cloning features of rolling update with
older versions of the database. Update your database to at least 5.3 using standard update before proceeding with rolling update.
Overview
Here is a hypothetical cluster setup:
If you want to execute system update, you need to shutdown the whole cluster. You end up with the following scenario:
This is custom documentation. For more information, please visit the SAP Help Portal
28
5/27/2022
To address this issue, SAP Commerce provides the rolling update feature. It is intended to help you to eliminate a cluster downtime during the system update. Each node has
to be restarted, therefore you need to provide a reliable session replication and/or request routing.
Cloning Type System
During a rolling update it is required for a while that multiple nodes work with different codebases and different type system de nitions. To allow old nodes to work correctly
we need to perform system update on a separate type system.
The type system used is determined by the db.type.system.name property. By default, it is set to DEFAULT, which means the default type system is used.
To copy the type system you currently use, execute:
ant createtypesystem -DtypeSystemName=new_type_system
When the codebase on the old node is updated, it becomes a new node. This new node must be started with the new type system.
 Note
The createtypesystem target copies only the type system - related data. Other data such as products or customers are not copied.
Deleting Outdated Type System
To delete your outdated type system, in the <HYBRIS_BIN_DIR>/platform directory, execute:
ant droptypesystem -DtypeSystemName=USER_DEFINED_TYPE_SYSTEM
Before you delete your outdated type system, make sure everything works properly. Backup your data for safety.
Potential Issues
Tasks and cronjobs introduced by the new codebase work properly only on the nodes with the new codebase. These tasks and cronjobs may fail on the nodes with the old
codebase.
 Note
To limit potential issues and to simplify the procedure, it is recommended that you shut down the background processing nodes.
Perform a Rolling Update
Follow these steps to learn how to perform a rolling update in a clustered environment.
Context
To perform a rolling update on a cluster, follow the steps:
Procedure
1. Execute the following command in the <HYBRIS_BIN_DIR>/platform directory to copy the current type system:
ant createtypesystem -DtypeSystemName=new_type_system
2. Update the new type system:
a. Add the db.type.system.name property in the local.properties le.
This is custom documentation. For more information, please visit the SAP Help Portal
29
5/27/2022
db.type.system.name=new_type_system
b. Execute the following command in the <HYBRIS_BIN_DIR>/platform directory:
ant updatesystem
3. For each node in the cluster, do the following:
a. Shut down the node.
b. Update the codebase for the selected node.
c. Add the db.type.system.name property in your local.properties le to con gure the node to use the new type system.
db.type.system.name=new_type_system
d. Start up the node in the cluster.
Results
You completed a rolling update procedure.
Perform a Rolling Update - Example with Two Nodes
Follow these steps to perform an example rolling update in a clustered environment with two nodes. You can watch a video showing how to do it.
Context
The following video demonstrates how to perform a rolling update on a SAP Commerce cluster with two nodes.
The example below shows how to perform the rolling update.
This is custom documentation. For more information, please visit the SAP Help Portal
30
5/27/2022
Procedure
Updating the First Node
1. Execute the following command to clone the current type system:
ant createtypesystem -DtypeSystemName=new_ts
The name of the new type system is de ned with the typeSystemName parameter value. In this example, the name of the new type system is new_ts.
2. Change the codebase and the type system in the rst node.
3. After changing the codebase, run:
ant clean all
On the rst node you have a new codebase and a new type system de nition in the items.xml les.
4. Change the value of the db.type.system.name property in your local.properties le to con gure the node to use the new type system:
db.type.system.name=new_ts
5. Make sure that you can see the following state of the rst node:
the new codebase
the new type system de nition
the node is con gured to use the cloned type system.
6. Execute the following command in the <HYBRIS_BIN_DIR>/platform directory:
ant updatesystem
You should have the node updated.
7. Start the rst node.
Updating the Second Node
8. Shut down the second node.
9. Change the value of the db.type.system.name property in the local.properties le to con gure Platform to use the updated type system:
db.type.system.name=new_ts
10. Change the codebase and the type system at the second node.
11. Run the following command after changing the codebase:
ant clean all
On the second node you have a new codebase and a new type system de nition in the items.xml les.
12. Start the second node.
Perform a Rolling Update - Example with Four Nodes
Perform an example rolling update on a cluster with four nodes.
Context
The cluster consists of four nodes working with an old codebase. Sessions are shared between the cluster nodes with a session replication mechanism.
Procedure
1. You need to copy the type system. To do so, execute ant createtypesystem -DtypeSystemName=new_type_system_name command. The name of new type
system is de ned with the typeSystemName parameter value.
This is custom documentation. For more information, please visit the SAP Help Portal
31
5/27/2022
2. Shut down the rst node in the cluster.
3. Change the codebase and the type system at the rst node.
4. After changing the codebase run ant clean all command. Therefore, on the rst node you have a new codebase and a new type system de nition in the
items.xml les.
5. When you start the rst node with the new type system, it takes part in a session replication.
6. Now repeat steps from 2 to 5 for the rest of your all nodes.
7. All your nodes in the cluster should work with the new type system.
This is custom documentation. For more information, please visit the SAP Help Portal
32
5/27/2022
Switching Between Clusters
Learn how to switch from a cluster working with an old type system to a cluster with a new type system.
In this scenario the two clusters share sessions by a session replication. There is an old and a new (updated) type system.
Cluster 1 works with the old type system serving all the requests. Cluster 2 is updated with the new codebase and con gured to work with the new (updated) type system.
Con gure the load balancer to use Cluster 2 instead of Cluster 1. Then, cluster 2 serves all the requests.
Related Information
Cluster - Technical Guide
Semi-Session Failover
Session failover is a mechanism to transfer an existing session to another cluster node than the one the session is assigned to. This is useful if the cluster node to which the
session was originally assigned goes offline, for example for planned maintenance or due to a hardware defect: Without a session failover mechanism, all data kept with
sessions on the offline cluster node would be lost.
 Note
Please note that Jalo has been deprecated.
In essence: with session failover, a cluster node can go offline and all of the sessions assigned to the cluster node will be transferred to other cluster nodes automatically and
without loss of data. A full session failover would reproduce every session on every cluster node. This is technically not feasible with SAP Commerce. Therefore, the
This is custom documentation. For more information, please visit the SAP Help Portal
33
5/27/2022
mechanism described here uses a different approach and does not replicate every session on every cluster node. Instead, this approach discussed here transfers sessionrelated data such as the logged-in user and the session's cart to a new session if the old session times out.
Semi-Session Failover Mechanism Description
The semi-session failover mechanism described in this document basically works like this:
When a web browser opens an HTTP connection to a web application, the resulting HTTP session gets an individual session ID.
The Cart type is extended to hold a eld for the HTTP session ID.
If a cluster node goes down, the load balancer makes sure that the HTTP connections that go to the offline node are redirected to another cluster node.
The new cluster node assigns a new HTTP session, and by consequence, a new HTTP session ID.
The cart of the "old" session that was created on the offline cluster node is still available, though.
The semi-session failover mechanism uses an extended implementation of the Commerce Platform Filters.
Extending the Commerce Platform Filters
 Note
The following content describes a functionality using ServiceLayer.
Every web extension module of an extension can hook into the Servlet lter chain. To hook into the Servlet lter chain, you need to implement a Java Servlet lter based on
the Filter interface. In this case you need to extend the Commerce Platform Filters used by your Web application following instruction from hybris Platform Filters, section
Con guring Existing Filters.
Building and Updating SAP Commerce
For all of these changes to take effect, you need to build and initialize or update SAP Commerce.
To build SAP Commerce:
Open a command shell.
Navigate to the ${HYBRIS_BIN_DIR} /platform directory.
Make sure that a compliant Apache Ant version is used:
On Windows systems, call the ${HYBRIS_BIN_DIR} /platform/setantenv.bat le. Do not close the command shell after this call as the settings
are transient and would get lost if the command shell is closed.
On Unix systems, call the ${HYBRIS_BIN_DIR} /platform/setantenv.sh le, such as: . ./setantenv.sh
Call ant clean all to build SAP Commerce entirely.
To update SAP Commerce:
1. Open the SAP Commerce Administration Console.
2. Go to the Platform tab and select Update option.
3. Click the Update button.
For more information, see:
hybris Administration Console - End User Guide
Initializing and Updating SAP Commerce
Related Information
JaloSession
http://java.sun.com/javaee/5/docs/api/javax/servlet/Filter.html
http://java.sun.com/products/servlet/Filters.html
hybris Platform Filters
About Extensions
Ordering Process
Cluster Improvements and ID Autodiscovery
Making cluster deployments - especially in cloud and virtualized environments - is easier after we have introduced some improvements in SAP Commerce clustering support.
Cluster ID Autodiscovery
Cluster autodiscovery is a feature that makes deployment less complex and more exible. All nodes that form a cluster can have an automatically assigned ID number. You
don't have to explicitly set the <cluster.id> property on each node.
This is custom documentation. For more information, please visit the SAP Help Portal
34
5/27/2022
To enable ID autodiscovery, set <cluster.nodes.autodiscovery> to <true> (it is disabled by default). This makes each new node query a database table to get information
about other nodes in the cluster and fetch the next available ID number.
Instances periodically ping each other and update node records in the database. The <cluster.nodes.ping.interval> property sets time interval between each heartbeat pulse.
Stalled or crashed nodes are removed from a cluster and new nodes can take their IDs. You can set the time after which a node that doesn't respond is considered down,
using the <cluster.nodes.stale.timeout> property. Both <cluster.nodes.ping.interval> and <cluster.nodes.stale.timeout> should be set to the same value in all nodes. The
<cluster.nodes.ping.interval> property must be smaller than <cluster.nodes.stale.timeout>.
 Caution
In case of a network loss, cluster IDs may be wrongly re-assigned to new instances.
ID Autodiscovery Properties
Property
Default value
Description
<cluster.nodes.autodiscovery>
<false>
Enables cluster node id autodiscovery.
<cluster.nodes.ping.interval>
<10000>
Time between pings that update informations about nodes.
<cluster.nodes.stale.timeout>
<30000>
Time after which a node is considered to be stale / crashed.
Must be bigger than <cluster.nodes.ping.interval>.
Related Information
Cluster - Technical Guide
Commerce Platform Search Mechanisms
Several search mechanisms are available in the Commerce Platform without any additional modules. These mechanisms are FlexibleSearch, GenericSearch and Lucene.
Here you will nd an overview of these mechanisms together with links to relevant documentation.
FlexibleSearch
Flexible Search searches SAP Commerce items. It retrieves items in an SQL-based query language. FlexibleSearch search results can be limited by restrictions.
Search Base
FlexibleSearch
Used for/Available in
the AdminWeb's FlexibleSearch JSP page
the SAP Commerce API
Pro
Returns a list of the SAP Commerce items
Result list is always up to date
Search parameters can be passed by a Java Map at run time
Con
Requires basic knowledge of the FlexibleSearch syntax, which in turn requires basic understanding of SAP
Commerce
Type System Errors in built query result in run-time errors
More information:
FlexibleSearch
Restrictions
The Type System
ViewType
ViewType is the SAP Commerce representation of a database view. It searches on SAP Commerce items. ViewType allows you to conveniently gather attributes from
different types, and to de ne parameters which will be passed to the FlexibleSearch statement at run time. ViewType is mostly used in reporting contexts within the Hybris
Management Console (HMC).
Search Base
FlexibleSearch
Used for/Available in
Used for the Inbox of the SAP Commerce Work ow Module
Pro
Returns a list of SAP Commerce items
Result list is always up to date
Search parameters can be passed to the ViewType at run time
Allows de ning a list of parameters
This is custom documentation. For more information, please visit the SAP Help Portal
35
5/27/2022
Con
Requires basic knowledge of the FlexibleSearch syntax, which in turn requires basic understanding of SAP
Commerce
More information:
FlexibleSearch
The Type System
work ow Extension
SavedQuery
SavedQuery allows you to run prede ned FlexibleSearch queries with variable parameters. It searches on SAP Commerce items, and cannot be used outside the HMC.
 Note
Not Related to Saved Queries in Cockpits Although the name might imply a relation, the SavedQueries in the HMC and the Saved Queries in the SAP Commerce Product
Cockpit (see also Product PerspectiveProduct Perspective) are different, unrelated concepts. In particular, HMC SavedQueries cannot be used in the SAP Commerce
Product Cockpit, and conversely.
Search Base
FlexibleSearch
Used for/Available in
Used for the Search Area in the HMC
Prede ned HMC-based search queries, such as " nd all products whose name or identi er contains the given string"
Pro
Returns a list of SAP Commerce items
Search parameters can be passed by the HMC at run time
Allows yout to de ne a list of parameters
Con
Works in the HMC only
Requires basic knowledge of the FlexibleSearch syntax, which in turn requires basic understanding of the SAP Commerce type
system
Errors in built query result in run-time errors
Parameters de ned cannot be left blank and must be speci ed
More information:
Managing SavedQuery Items in the Hybris Management Console
FlexibleSearch
The Type System
AdvancedSavedQuery
AdvancedSavedQuery allows you to run prede ned FlexibleSearch queries with variable parameters. It is more exible than SavedQuery, allowing the speci cation of empty
parameters, for example. AdvancedSavedQuery searches SAP Commerce items.
Search Base
Used for/Available in
FlexibleSearch
Used for the Search Area in the HMC
Prede ned HMC-based search queries with optional parameters, such as " nd all customers for which e-mail address, shipping address, country,
or name matches the search string".
Pro
Returns a list of SAP Commerce items
Result list is always up to date
Search parameters can be passed by the HMC at run time
Allows you to de ne a list of parameters
Unlike SavedQuery, de ned parameters can be left blank and do not have to be speci ed
Con
Works in the HMC only
Requires basic knowledge of the FlexibleSearch syntax, which in turn requires basic understanding of the SAP Commerce type system
Errors in built query result in run-time errors
More information:
advancedsavedquery Extension
FlexibleSearch
This is custom documentation. For more information, please visit the SAP Help Portal
36
5/27/2022
The Type System
GenericSearch
Generic Search searches SAP Commerce items. It wraps FlexibleSearch into Java Objects. The HMC search area uses GenericSearch.
Search Base
FlexibleSearch
Used for/Available in
Used for the Search Area in the HMC
Pro
Unlike FlexibleSearch statements, errors in built query result in compile-time errors
Returns a list of SAP Commerce items
Result list is always up to date
Search parameters can be passed by a Java Map at run time
Con
Even though the FlexibleSearch queries are built via Java objects, GenericSearch still requires a basic knowledge of
FlexibleSearch
More information:
GenericSearch
LuceneSearch
LuceneSearch is a fast, index-based full-text search. It does not search on SAP Commerce items directly, but searches indexes instead and only returns text results.
Search Base
Lucene
Used for/Available in
Used as HMC-based Quicksearch
Used as the Hybris Print Cockpit search
Used as the SAP Commerce StoreFoundation search
Pro
Does not require knowledge of the FlexibleSearch syntax
Fast search over large sets of text
Open-source search engine
Indexes can be con gured exibly
Con
Returns full text, not a list of SAP Commerce items
Result list only as up to date as the last index rebuild
Index rebuild takes some time to complete
More information:
Working with Lucene Search
lucenesearch Extension
advancedsavedquery Extension
The advancedsavedquery extension extends the Hybris Management Console's (HMC) SavedQuery functionality.
 Note
An SAP Commerce extension may provide functionality that is licensed through different SAP Commerce modules. Make sure to limit your implementation to the
features de ned in your contract license. In case of doubt, please contact your sales representative.
General Overview on the AdvancedSavedQuery
The AdvancedSavedQuery is an improved version of the Hybris Management Console SavedQuery that
1. Enables optionally skipping parameters automatically for which no value has been provided
In a SavedQuery, a search value needs to be provided for each attribute to search. Failing to provide a search value for an attribute causes the SavedQuery to fail. For
example, with the SavedQuery it is not possible to handle all of the following cases in a single screen form:
nd all orders placed prior to a certain date
nd all orders placed between two given dates
nd all orders placed after a certain date
as this would require two individual elds to enter the time range. If only either eld was available, the user would not be able to specify a time span; if both
elds were available, the user would not be able to leave either eld blank because this would cause the SavedQuery to fail. An AdvancedSavedQuery can be
This is custom documentation. For more information, please visit the SAP Help Portal
37
5/27/2022
con gured to ignore parameters for which no search value has been provided.
2. Enables using the same attribute multiple times under different labels A SavedQuery allows using an attribute of another type only once. Using a SavedQuery to
search for AbstractOrder modi ed within a certain time span from the Order type is not possible because the attribute to search for (modi edtime) would have to be
referenced twice: for the beginning of the time span and for the end of the time span. However, modi edtime is an attribute of the AbstractOrder type and therefore
can be referenced only once when running a SavedQuery on the Order type. By using automatically generated labels for attributes on other types, the
AdvancedSavedQuery allows using any number of attributes on other types.
3. Enables searching on attributes on related types (such as nding an order by the zip code stored with a customer's address)
As the AdvancedSavedQuery is translated into a FlexibleSearch query on every run, it requires more processing power than SavedQuerie s or the equivalent FlexibleSearch
statement alone, and, by consequence, creates more load on the SAP Commerce server. Also, setting up AdvancedSavedQueries from the code level is a rather complex
matter. To construct search queries via the API, use the FlexibleSearch instead of the AdvancedSavedQuery.
The AdvancedSavedQuery is useful for front end applications where end users are to enter values for search queries and where the query is supposed to run no matter if a
value for a certain parameter was given or not.
Function Overview
Technical Overview and Type Model
An AdvancedSavedQuery consists of an AdvancedSavedQuery object holding a Wherepart object. This Wherepart object is the actual WHERE part of the
AdvancedSavedQuery and holds a Collection of ComposedTypeAdvancedSavedQuerySearchParameter and / or TypedAdvancedSavedQuerySearchParameter objects.
Type Name
Type Localization in the HMC
Type Usage
ComposedTypeAdvancedSavedQuerySearchParameter
ComposedType Search Parameter
For attributes on the same type as the type in the
AdvancedSavedQuery
TypedAdvancedSavedQuerySearchParameter
Result Type Search Parameter
For attributes on a different type than the type in the
AdvancedSavedQuery
 Note
An optional attribute allows using a LOWER operator on an individual AdvancedSavedQuerySearchParameter. If the lower attribute is set to true (default), the individual
AdvancedSavedQuerySearchParameter will be enclosed in a LOWER operation.
Syntax
The AdvancedSavedQuery is based on SAP Commerce FlexibleSearch. The basic syntax is like this:
SELECT {attribute} FROM {type} WHERE <param>
SELECT {o.pk} FROM {$$$ AS o LEFT JOIN User AS u ON {o.user}={u.pk} } WHERE <param>
SELECT {c.pk} FROM {$$$ AS c JOIN Address AS a ON {c.defaultShipmentAddress}={a.pk}} WHERE <param>
The <param> parameter is one of the major differences between the AdvancedSavedQuery and the SavedQuery. In a SavedQuery, every parameter needs to be speci ed
explicitly in the query. An AdvancedSavedQuery allows an overall reference to a parameter collection. This parameter collection consists of the attributes to search plus an
attribute that states whether the attributes are connected by AND or by OR. This setting affects every parameter; it is not possible to connect some parameters by AND
and other parameters by OR.
By the time the AdvancedSavedQuery is run, the <param> parameter is resolved and the entire AdvancedSavedQuery is translated into a FlexibleSearch statement. For
example, the default OrderQuery AdvancedSavedQuery has this basic syntax:
This is custom documentation. For more information, please visit the SAP Help Portal
38
5/27/2022
SELECT {o.pk} FROM {$$$ AS o LEFT JOIN User AS u ON {o.user}={u:pk} } WHERE <param>
and will be translated into the FlexibleSearch statement
SELECT {o.pk} FROM {$$$ AS o LEFT JOIN User AS u ON {o.user}={u:pk} } WHERE
{o.status} = ?AbstractOrder.status91712
OR {o.code} LIKE ?AbstractOrder.code91968
OR {o.date} >= ?AbstractOrder.date91969
OR {o.date} <= ?AbstractOrder.date92224
OR {o.modifiedtime} >= ?AbstractOrder.modifiedtime92225
OR {o.modifiedtime} <= ?AbstractOrder.modifiedtime92226
OR {o.user} = ?AbstractOrder.user92464
During translation of the AdvancedSavedQuery into a FlexibleSearch statement, random numbers are suffixed to the parameter references (so that
AbstractOrder.modi edtime becomes ?AbstractOrder.modi edtime92225, for example). This is since the list of parameters is passed to the FlexibleSearch as a Map, and
Java Maps do not allow duplicate references. In other words, if no random suffix were attached to the parameter references, each parameter could be used only once
because the Map would not allow using a parameter more than once. By suffixing a random number to the parameter reference, the Map only contains unique reference and
no removal takes place.
To create an AdvancedSavedQuery that is applicable for several types, use the wildcard characters $$$ as a type, as in the following code sample:
SELECT {pk} FROM { $$$ } WHERE <param>
The effect of an unspeci ed parameter depends on the setting of the emptyHandling attribute of the parameter:
emptyHandling Attribute Value
Effect
AsIs
Leaves the parameter in the AdvancedSavedQuery even if empty.
Ignore
Skips the parameter if empty (null) when the AdvancedSavedQuery is transformed into a
FlexibleSearch statement. A parameter string consisting of spaces only is not ignored.
Trim and ignore
A String is not null if it consists of a single space. On the other hand, a String consisting of
just a number of spaces is very much empty. Using Trim and ignore causes any leading and
trailing spaces to be removed and skips the parameter if empty when the
AdvancedSavedQuery is transformed into a FlexibleSearch statement.
AdvancedSavedQuery Samples
SAP Commerce comes with two pre-implemented AdvancedSavedQuery samples: the Extended Order Search (OrderQuery) and the Extended Customer Search
(SearchCustomerQuery).
OrderQuery
This query uses the functionality of the AdvancedSavedQuery to allow searching orders that have been modi ed after a certain date (modi ed after) or prior to a certain
date (modi ed before). In both cases, the same attribute (modi edtime) is used. Using a single attribute twice is not possible with the SavedQuery.
AdvancedSavedQuery statement:
SELECT {o.pk} FROM {$$$ AS o LEFT JOIN User AS u ON {o.user}={u:pk} } WHERE <param>
Resulting FlexibleSearch statement:
SELECT {o.pk} FROM {$$$ AS o LEFT JOIN User AS u ON {o.user}={u:pk} } WHERE
{o.status} = ?AbstractOrder.status91712
OR {o.code} LIKE ?AbstractOrder.code91968
OR {o.date} >= ?AbstractOrder.date91969
OR {o.date} <= ?AbstractOrder.date92224
OR {o.modifiedtime} >= ?AbstractOrder.modifiedtime92225
OR {o.modifiedtime} <= ?AbstractOrder.modifiedtime92226
OR {o.user} = ?AbstractOrder.user92464
This is custom documentation. For more information, please visit the SAP Help Portal
39
5/27/2022
SearchCustomerQuery
This query uses the functionality of the AdvancedSavedQuery to allow searching the zip code of customer addresses (Postal code). Zip codes (postal codes) in SAP
Commerce are not stored with the Customer type, so searching zip codes via a SavedQuery would not possible.
AdvancedSavedQuery statement:
SELECT {c.pk} FROM {$$$ AS c JOIN Address AS a ON {c:defaultShipmentAddress}={a:pk}} WHERE <param>
Resulting FlexibleSearch statement:
SELECT {c.pk} FROM {$$$ AS c JOIN Address AS a ON {c:defaultShipmentAddress}={a:pk}} WHERE
{c.name} LIKE ?Customer.name90720
AND {a.postalcode} LIKE ?Address.postalcode90960
AND {a.country} = ?Address.country91216
AND {a.email} = ?Address.email91217
Using the Mechanism Outside the HMC
The usage of the advanced search query is not limited to the HMC only. Since its logic belongs to an API which is independent from the HMC you can use the mechanism in
any other part of your system as well.
AdvancedQuery Setup via API
public void setupQuery()
{
final ModelService modelService = new DefaultModelService();
final TypeService typeService = new DefaultTypeService();
This is custom documentation. For more information, please visit the SAP Help Portal
40
5/27/2022
final
final
final
final
ComposedTypeModel
ComposedTypeModel
ComposedTypeModel
ComposedTypeModel
orderType = typeService.getComposedTypeForCode(OrderModel._TYPECODE);
abstractOrderType = typeService.getComposedTypeForCode(AbstractOrderModel._TYPECODE);
userType = typeService.getComposedTypeForCode(UserModel._TYPECODE);
employeeType = typeService.getComposedTypeForCode(EmployeeModel._TYPECODE);
final AdvancedSavedQueryModel queryModel = modelService.create(AdvancedSavedQueryModel.class);
queryModel.setCode("OrderQuery");
queryModel.setResultType(orderType);
queryModel.setQuery("SELECT {o." + OrderModel.PK + "} FROM {" + orderType.getCode() + " AS o LEFT JOIN " + userType.getCode()
+ " AS u ON {o." + AbstractOrderModel.USER + "}={u:" + de.hybris.platform.jalo.user.User.PK + "} "
+ "LEFT JOIN " + employeeType.getCode() + "* AS v ON {o.PlacedBy}={v." + EmployeeModel.PK + "}} WHERE <param>");
queryModel.setName("Extended Order Search");
modelService.save(queryModel);
final WherePartModel wherePartModel = modelService.create(WherePartModel.class);
wherePartModel.setSavedQuery(queryModel);
wherePartModel.setReplacePattern("<param>");
wherePartModel.setAnd(Boolean.TRUE);
modelService.save(wherePartModel);
ComposedTypeAdvancedSavedQuerySearchParameterModel parameterModel =
modelService.create(ComposedTypeAdvancedSavedQuerySearchParameterModel.class);
parameterModel.setWherePart(wherePartModel);
parameterModel.setComparator(AdvancedQueryComparatorEnum.EQUALS);
parameterModel.setJoinAlias("o");
parameterModel.setEmptyHandling(EmptyParamEnum.IGNORE);
parameterModel.setTypedSearchParameter(typeService.getAttributeDescriptor(abstractOrderType, AbstractOrderModel.STATUS));
modelService.save(parameterModel);
parameterModel = modelService.create(ComposedTypeAdvancedSavedQuerySearchParameterModel.class);
parameterModel.setWherePart(wherePartModel);
parameterModel.setComparator(AdvancedQueryComparatorEnum.CONTAINS);
parameterModel.setJoinAlias("o");
parameterModel.setEmptyHandling(EmptyParamEnum.IGNORE);
parameterModel.setTypedSearchParameter(typeService.getAttributeDescriptor(abstractOrderType, AbstractOrderModel.CODE));
modelService.save(parameterModel);
}
Related Information
Commerce Platform Search Mechanisms
FlexibleSearch
Hybris Management Console
FlexibleSearch
SAP Commerce comes with a built-in query language of a SQL-based syntax, FlexibleSearch. FlexibleSearch enables searching over the items in SAP Commerce.
Basics
FlexibleSearch is a powerful retrieval language built into SAP Commerce. It enables searching for SAP Commerce types and items using an SQL-based syntax. The execution
of a FlexibleSearch statement takes place in two phases: pre-parsing into an SQL-compliant statement and running that statement on the database. During the pre-parsing
phase, the FlexibleSearch framework resolves the FlexibleSearch syntax into SQL-compliant syntax. For example, the following two code snippets show a FlexibleSearch
query and the statement that results from the FlexibleSearch query, which is executed on the database:
For more information, see:
Type System Documentation
FlexibleSearch query:
select {pk}, {code}, {name[de]} from {Product}
SQL statement (executed on the database):
SELECT
item_t0.PK , item_t0.Code , lp_t0.p_name
FROM products item_t0 JOIN productslp lp_t0 ON item_t0.PK = lp_t0.ITEMPK AND lp_t0.LANGPK= 9013632135395968
WHERE (item_t0.TypePkString IN
( 23087380955301264 , 23087380955663520 , 23087380955662768 , 23087380955661760 ,
23087385363574432 , 23087380955568768 , 23087380955206016 ) )
FlexibleSearch abstracts the SAP Commerce type system from the actual database tables so that you can run searches on the type system level. Unlike on conventional
SQL statements, in a FlexibleSearch query, you do not have to specify explicit database table names. The FlexibleSearch framework resolves type and database table
dependencies automatically and speci es UNIONS and JOINS where necessary. The entire conversion process between type system and database representation takes
place automatically. To access a type in a FlexibleSearch query, surround the type code with curly braces { and }, as in:
SELECT * FROM {Product}
 Note
FlexibleSearch queries are executed on the database directly using SQL statements. By consequence, it is not possible to run FlexibleSearch queries on jalo-only
attributes as these attributes are not written into the database. Find more information in the Jalo-only Attributes document.
This is custom documentation. For more information, please visit the SAP Help Portal
41
5/27/2022
SAP Commerce executes FlexibleSearch queries in the context of a certain user account, using a session. As different user accounts have access to different items on SAP
Commerce, the number of search results depends on the user account. The number of search results is de ned by type access rights (these affect the Hybris Management
Console search results only), restrictions, catalog versions, and categories, for example. The more privileged a user account is, the more search results a FlexibleSearch
yields in the context of that user account. By default, the user account assigned to a session is anonymous, so any FlexibleSearch query returns the search results matching
the anonymous account by default. To run FlexibleSearch queries in the context of a user account different from anonymous, the session needs to be assigned to a different
user account, such as:
import de.hybris.platform.servicelayer.user.UserService;
...
// Injected by Spring
userService.setCurrentUser(userService.getUserForUID("myUserAccount"));
...
Syntax Overview
The basic syntax of a FlexibleSearch query looks like this:
SELECT <selects> FROM <types> ( WHERE <conditions> )? ( ORDER BY <order> )?
A FlexibleSearch query consists of:
The mandatory <selects> parameter for the SELECT clause.
The mandatory <types> parameter for the FROM clause.
An optional <conditions> eld for the WHERE clause.
An optional ORDER BY clause.
SQL Command / Keyword
Description / Comment
Code Example
ORDER BY {alias:attribute}
Display results ordered by the value of attribute.
SELECT ... FROM ... ORDER BY...
ASC
Sort results in ascending order (a...z, 0...9).
SELECT ... FROM ... ORDER BY ... ASC
DESC
Sort results in descending order (z...a, 9...0).
SELECT ... FROM ... ORDER BY ... DESC
DISTINCT
Eliminates double entries in the query result.
SELECT DISTINCT ... FROM ...
OR
Performs a logical OR compare between two queries.
... WHERE ... OR ...
AND
Performs a logical AND compare between two queries.
... WHERE ... AND ...
IS [NOT] NULL
Returns the results that are [not] null
... WHERE ... IS [NOT] NULL
[NOT] IN
Returns the results that are [not] part of the following
statement ... WHERE ... [NOT] IN ...
[NOT] EXISTS
Returns the results that are [not] matching a given
...WHERE ... EXISTS ( {{ SELECT ... }} )
subquery.
LIKE
Compares to a pattern.
... WHERE ... LIKE '...'
%
Wildcard matching any number of characters.
... WHERE ... LIKE '%...'||'...%...'||'...%'
_
Wildcard matching a single character.
... WHERE ... LIKE '...' || '......'
||'..._'
LEFT JOIN ON
Merges two tables into one.
... LEFT JOIN ... ON ... = ...
=
True if results are equal.
!=, <>
True if results are not equal.
<
True if result 1 is less than result 2.
<=
True if result 1 is equal to or less than result 2.
>
True if result 1 is greater than result 2.
>=
True if result 1 is equal to or greater than result 2.
CONCAT
Concatenates two results - the example on the right hand
side would return the string result.
NCONCAT ( 'resul', 't' )
Note that SQL Server
2012 doesn't provide a CONCAT function. Strings are
connected via '+', for example 'foo' + 'bar' instead.
:o
Outer join parameter is used to include matches with
missing rows in the ProductsLP table (=. the table that
holds localized products) as well. Otherwise, the example
query would only return products with an existing row in
ProductsLP table, because it would only use JOIN.
SELECT {p:PK}
FROM {Product AS p}
WHERE {p:description[en]:o} LIKE '%text%'
OR {p:description[de]:o} LIKE '%text%'
This is custom documentation. For more information, please visit the SAP Help Portal
42
5/27/2022
SQL Command / Keyword
Description / Comment
{locAttr[ANY] }
A special version of a localized attribute condition, where
an item is returned if any localization record holds a value
for that attribute which ful lls the given condition
regardless of the actual language. Technically, this means
Code Example
SELECT DISTINCT {p:PK}
FROM {Product AS p}
WHERE {p:description[ANY]} LIKE '%hybris%'
that the LP table is joined without a language parameter,
which means that the same item may occur multiple times
in the search result! You should use DISTINCT to
compensate.
<selects>
The values for the <selects> eld specify the database columns to be returned. The asterisk (*) returns all database columns, as by SQL convention. To search for an
attribute, specify the attribute identi er in curly braces, such as: SELECT {code} FROM {Product}.
To retrieve values of localized attributes, use the language identi er as a suffix in the attribute name, enclosed in squared brackets ([ and ]), such as:
SELECT {name[de]}, {name[en]} FROM {Product}
Find two examples of different queries:
SELECT * FROM {Category}
This query returns every database column from the Category table.
SELECT {pk},{code},{name[de]} FROM {Product}
This query returns the database columns pk, code, and the German localized entries of the name column [de] from the Product table.
<types>
The values for the <types> eld in the FROM clause specify SAP Commerce types, nested in curly braces { and } which are to be searched, such as:
SELECT * FROM {Product}
SELECT * FROM {Category JOIN Catalog}
You can specify an alias to be used for distinguishing attribute elds, using the AS operator:
SELECT {p.code} FROM {Product AS p} ORDER BY {p.code}
You may also run JOIN and LEFT JOIN queries, as in:
SELECT {cj.code}
FROM {SyncItemCronJob AS sicj
JOIN SyncItemJob AS sij
ON {sicj:job} = {sij:pk}
}
SELECT {p1.PK},{p2.PK}
FROM {Product AS p1
LEFT JOIN Product AS p2
ON {p1.code} = {p2.code}
}
WHERE {p1.PK} <> {p2.PK}
ORDER BY {p1.code} ASC
Always remember that it is most important that the whole <types> block must be enclosed by { and } no matter how many types are actually inside it. Do not try to put in
multiple <types> blocks in the FROM clause. Even though this may appear to be working, it may cause unpredictable errors.
Searching Subtypes
By default, specifying a type to search causes a FlexibleSearch query to search that type and any subtypes. For example, the following code snippet returns the codes and
the PKs of all instances of Product and VariantProduct:
SELECT {code},{pk} FROM {Product}
By adding a trailing exclamation mark ( ! ), the FlexibleSearch query searches only the speci ed type and omits all subtypes. For example, the following code snippet
searches only instances of Product, not of VariantProduct:
SELECT {code},{pk} FROM {Product!}
This is custom documentation. For more information, please visit the SAP Help Portal
43
5/27/2022
When searching for subtypes, the FlexibleSearch rst retrieves the subtypes to search, for example in the case of Product, types to search are Product and
VariantProduct. As a type de nition in SAP Commerce is an item and therefore has a Primary Key (PK), the FlexibleSearch retrieves the PK of all types to search. The list
of the PKs of the types to search is put into an IN clause within the WHERE clause.
FlexibleSearch Query
SQL Statement
SELECT {p:code}, {p:pk}
SELECT
FROM {Product AS p}
FROM products item_t0
item_t0.Code , item_t0.PK
WHERE (item_t0.TypePkString IN
(
23087380955301264 , 23087380955663520 , 23087380955662768 ,
23087380955661760 , 23087385363574432 , 23087380955568768 ,
23087380955206016 )
)
SELECT {p:code}, {p:pk}
SELECT
FROM {Product! AS p}
FROM products item_t0
item_t0.Code , item_t0.PK
WHERE (item_t0.TypePkString =
23087380955206016 )
 Note
In the code above, the use of ':' is the legacy alternative to '.' and is still supported for backward compatibility and a few special features.
Excluding Types from a Search
If you want to make sure that certain types are omitted from a FlexibleSearch query run, there are two approaches at your disposal:
Using the itemtype operator and a parameter.
This approach is feasible if you can prepare and pass a Map with references to the types you want to exclude as a FlexibleSearch parameters, such as:
final Set<ComposedTypeModel> excludedTypes = new HashSet<ComposedTypeModel>();
excludedTypes.add(getComposedType("mySuborderType"));
StringBuilder queryString = new StringBuilder("SELECT {").append(OrderModel.PK).append("} ");
queryString.append("FROM {").append(OrderModel._TYPECODE).append("} ");
queryString.append("WHERE {").append(OrderModel.ITEMTYPE).append("} NOT IN (?excluded)");
final FlexibleSearchQuery query = new FlexibleSearchQuery(queryString.toString(), Collections.singletonMap("excluded", excludedTy
Using a JOIN clause
This approach is feasible if you cannot pass parameters, for example, because you need to enter a FlexibleSearch statement directly:
SELECT {o.PK} FROM {Order AS o JOIN ComposedType AS t ON {o.itemtype}={t.PK} }
WHERE {t.code} NOT IN ( 'Foo', 'Bar' )
<conditions>
The values for the <conditions> eld in the optional WHERE clause narrow down the number of matches by specifying at least one condition that is matched by all search
results.
 Note
Avoid Spaces in Search Condition Terms
Make sure to avoid spaces at the beginning and end of the search condition term, as = 'al' and = 'al ' are not identical search conditions and cause different search
results.
SELECT * FROM {Product} WHERE {code} LIKE '%al%'
Using the common SQL boolean operators ( AND, OR ) you can connect conditions, such as:
SELECT * FROM {Product} WHERE {code} LIKE '%al%' AND {code} LIKE '%15%'
Use the IS NULL operator to nd all entries that have no value:
SELECT * FROM {Product} WHERE {code} IS NULL
Negating a condition is possible using the SQL boolean operators NOT:
SELECT * FROM {Product} WHERE {code} NOT LIKE '%al%'
It is possible to combine negating and connecting conditions:
SELECT * FROM {Product} WHERE {code} LIKE '%al%' AND {code} NOT LIKE '%15%'
This is custom documentation. For more information, please visit the SAP Help Portal
44
5/27/2022
The negation of the IS NULL operator is IS NOT NULL:
SELECT * FROM {Product} WHERE {code} IS NOT NULL
The WHERE clause also allows sub-selects using double curly braces ( {{ and }} ), such as:
SELECT {cat:pk} FROM {Category AS cat} WHERE NOT EXISTS (
{{ SELECT * FROM {CategoryCategoryRelation} WHERE {target}={cat:pk} }} /* Sub-select */
)
<order>
The FlexibleSearch complies with the SQL syntax in terms of ordering results. By specifying an attribute in an ORDER BY clause, the list of search results are sorted
according to the speci ed type. In addition, you can optionally specify ASC to sort the search results in ascending order (null, 0 through 9, A through Z) or DESC to sort the
search results in descending order (Z through A, 9 through 0, null). ASC and DESC are mutually exclusive, ASC is default. Examples:
The following FlexibleSearch query sorts the search results by the values of the code database column, in descending order:
SELECT {code},{pk} FROM
{Product} ORDER BY {code} DESC
The following FlexibleSearch query sorts the search results by the values of the code database column, in ascending order: ( ASC is default order):
SELECT {code},{pk} FROM
{Product} ORDER BY {code}
Parameters
A FlexibleSearch query optionally contains parameters, marked by a pre xed question mark. Parameters enable you to pass values into the FlexibleSearch query. For
example, in the following code snippet, the parameter product can be used to pass a search pattern:
SELECT {p:pk} FROM {Product AS p} WHERE {p:code} LIKE ?product
The following FlexibleSearch query has two parameters, startDate and endDate:
SELECT {pk} FROM {Product} WHERE {modifiedtime} >= ?startDate AND {modifiedtime} <=?endDate
No-Cache Mode for FlexibleSearch
By default, FlexibleSearch heavily uses cache for storing search results. In most cases, this behaviour is desirable but sometimes it is better to skip cache completely. For
instance, when a query contains a frequently changing parameter such as current time in milliseconds, or a query result is really huge and actually would pollute cache. Now,
the FlexibleSearchService allows you to easily skip cache on demand. The following code example shows how to do that:
final FlexibleSearchQuery fQuery = new FlexibleSearchQuery("SELECT {PK} FROM {Foo} WHERE {modificationTime}=?modificationTime");
fQuery.addQueryParameter("modificationTime", Long.valueOf(System.currentTimeMillis()));
fQuery.setDisableCaching(true);
final SearchResult<FooModel> searchResult = flexibleSearchService.search(fQuery);
By simply using the setDisableCaching method on a FlexibleSearchQuery object, you are instructing FlexibleSearch to skip cache just for the current query.
Please keep in mind that type Foo used in the example above is an arti cial one.
Using FlexibleSearch Using the SAP Commerce API
Using FlexibleSearch queries using the SAP Commerce API takes place in two steps, both of which can be done in one Java statement:
1. Setting up the query
2. Running the query.
Constructing a FlexibleSearch Query
A FlexibleSearch query is constructed as a string which contains the query, such as:
final String query = "SELECT {pk} FROM {Product}"
// Flexible search service injected by Spring
final SearchResult<ProductModel> searchResult = flexibleSearchService.search(query);
To refer to a SAP Commerce type attribute in the FlexibleSearch query such as the primary key (PK) of an item, you need to reference the attribute when constructing the
query. In cases where the attribute is clear without ambiguity, specifying the attribute alone is enough. Still, it is recommended to reference the type of the attribute as well
for disambiguity. SAP Commerce resolves and translates the attribute reference automatically into the FlexibleSearch query:
This is custom documentation. For more information, please visit the SAP Help Portal
45
5/27/2022
Examples:
Java Code
FlexibleSearch
final String query = "SELECT {" + ProductModel.PK + "} FROM {" + ProductModel._TYPECODE + "}";
SELECT {pk} FROM {Product}
String query =
SELECT {p:pk} FROM {Product AS p}
"SELECT {p:" + ProductModel.PK + "} FROM {" + ProductModel._TYPECODE + " AS p}\n"+
WHERE {variantType} IS NOT NULL
"WHERE {" + ProductModel.VARIANTTYPE + "} IS NOT NULL"
Calling a FlexibleSearch
 Tip
Use Paging on Queries with Many Results
If you run a FlexibleSearch query that potentially returns more than 50 search results, be sure to use the paging mechanism of the FlexibleSearch described in the Hints
section below.
To call a FlexibleSearch statement using the API use flexibleSearchService, which is always available through the Spring, and has to be properly injected to your
service as follows:
<bean id="myFancyService" class="de.hybris.platform.foobar.MyFancyService" >
<property name="flexibleSearchService" ref="flexibleSearchService"/>
</bean>
public class MyFancyService implements FancyService
{
...
private FlexibleSearchService flexibleSearchService;
@Required
public void setFlexibleSearchService(final FlexibleSearchService flexibleSearchService)
{
this.flexibleSearchService = flexibleSearchService;
}
...
}
The flexibleSearchService search(...) methods returns a de.hybris.platform.servicelayer.search.SearchResult instance, which holds a List of
the individual search results. To access this List, call the SearchResult class getResult() method, such as:
final String query = "SELECT {" + ProductModel.PK + "} FROM {" + ProductModel._TYPECODE + "}";
final SearchResult<ProductModel> searchResult = flexibleSearchService.search(query);
List<ProductModel> result = searchResult.getResult();
You can then process this Collection instance like any other Collection instances:
final String query = "SELECT {" + ProductModel.PK + "} FROM {" + ProductModel._TYPECODE + "}";
final SearchResult<ProductModel> searchResult = flexibleSearchService.search(query);
final ProductModel product = searchResult.getResult().iterator().next();
 Caution
The Collection returned by SearchResult.getResult() uses the lazy translation approach. At rst access to a collection element, the element is translated to an
item.
In case the item was removed between gathering of the search result and translation of the speci c element, the returned collection has a null value at this position.
Passing Parameters
To pass parameters, create a Map instance holding the parameters and pass the Map to the search( ...) method, as in:
 Tip
If you do not need to pass parameters to the query, you can pass null for the parameter map.
final Map<String, Object> params = new HashMap<String, Object>();
String query =
"SELECT {" + PriceRowModel.PK + "} FROM {" + PriceRowModel._TYPECODE "} "+
"WHERE {" + PriceRowModel.PRODUCT
+ "} = ?product AND "+
"{" + PriceRowModel.NET
+ "} = ?net AND "+
"{" + PriceRowModel.CURRENCY
+ "} = ?currency AND "+
"{" + PriceRowModel.UNIT
+ "} = ?unit AND "+
"{" + PriceRowModel.UNIT_FACTOR + "} = ?unitfactor AND "+
"{" + PriceRowModel.UG
+ "} = ?userpricegroup AND "+
This is custom documentation. For more information, please visit the SAP Help Portal
46
5/27/2022
"{" + PriceRowModel.MIN_QUANTITY + "} = ?minquantity AND "+
"{" + PriceRowModel.PRICE
+ "} = ?price ";
params.put("product",
params.put("net",
params.put("currency",
params.put("unit",
params.put("unitfactor",
params.put("userpricegroup",
params.put("minquantity",
params.put("price",
product);
priceCopy.isNet());
priceCopy.getCurrency());
priceCopy.getUnit());
priceCopy.getUnitFactor());
priceCopy.getUserPriceGroup());
priceCopy.getMinQuantity());
priceCopy.getPriceValue());
final SearchResult<PriceRowModel> searchResult = flexibleSearchService.search(query, params);
 Note
If your query uses the statement ?product, then the key in the parameter map has to be product (without the ? ).
Instantiating of Search Results
If you retrieve only the PK database column (that is, only the PKs of SAP Commerce items), and provide the kind of type as a Java class, you can immediately cast the
models represented by the PKs into the actual model instances. In other words, executing the following code returns a Collection of CatalogModel instances, not a
Collection of PKs:
final String query = "SELECT {" + CatalogModel.PK + "} FROM {" + CatalogModel._TYPECODE + "} ORDER BY {" + CatalogModel.PK + "} ASC";
final SearchResult<CatalogModel> searchResult = flexibleSearchService.search(query);
If you retrieve more than one database column, you receive several individual entries per row of result and you will not be able to cast the search result into item instances
directly, not even if one of the database columns retrieved is the PK column.
Using the FlexibleSearch Using the Hybris Management Console
Triggering FlexibleSearch queries within the Hybris Management Console is possible in two ways: using SavedQuery instances and using ViewType instances.
A ViewType instance is SAP Commerce representation of a database view. A SavedQuery instance is a means of using a FlexibleSearch query to retrieve items in the SAP
Commerce instead of using the GenericSearch. The ViewType representation in the HMC is called Report De nition. The SavedQuery instance is the HMC representation
only, it must specify a resulttype and is available only for searches on resulttype and resulttype subtypes. It is available for every type in SAP Commerce.
For more information, see Wikipedia on database view
Creating a SavedQuery
Go to Managing SavedQuery Items in the hybris Management Console document, section Creating a SavedQuery, for details on how to create a SavedQuery using the
Hybris Management Console.
Using a SavedQuery
Go to Managing SavedQuery Items in the hybris Management Console document, section Using a SavedQuery, for details on how to call a SavedQuery using the HMC.
Creating a Report De nition
Go to the Creating Report De nitions Using the hybris Management Console document for details on how to create a Report De nition using the HMC.
Hints
Paging of Search Results
Some FlexibleSearch queries run the risk of returning a very large number of search results, such as SELECT * FROM {Products} WHERE {code} LIKE ?search
OR {name} LIKE ?search, where ?search is a parameter from a text eld. Managing more than some 50 or 100 search results in one single Collection is complicated
and performs comparably slow. For this reason, the FlexibleSearch framework offers a paging mechanism.
To use this paging mechanism, use the search(...) method with FlexibleSearchQuery object as parameter. You have to set on FlexibleSearchQuery the
setNeedTotal to true. If this parameter is set to true, the FlexibleSearch framework splits the number of returned search results into pages. Using the start and
range parameters, you can retrieve pages of search results. The following code snippet, for example, iterates over all the search results of the FlexibleSearch query, three
at a time:
int start = 0;
final int range = 3;
int total;
This is custom documentation. For more information, please visit the SAP Help Portal
47
5/27/2022
String query = "SELECT {" + UnitModel.PK + "} FROM {"+ UnitModel._TYPECODE + "} ORDER BY " + UnitModel._TYPECODE;
final FlexibleSearchQuery fQuery = new FlexibleSearchQuery(query);
fQuery.setCount(range);
fQuery.setNeedTotal(true);
do
{
fQuery.setStart(start);
final SearchResult<LanguageModel> searchResult = flexibleSearchService.search(fQuery);
total = searchResult.getTotalCount();
start += range;
}
while(start < total);
Be aware that every navigation, either backward or forward, through a paged search result triggers a new search query on the database. Internally, the FlexibleSearch runs
the query in full and uses an offset parameter to specify the portion of all search results to return. The fact that every navigation causes a database query has three major
consequences:
1. Complex queries cause heavy load on the database:
Executing a simple SELECT statement is rather fast, even with millions of search results. However, if your FlexibleSearch query requires JOIN or UNION to execute,
load on the database (and, by consequence, response times) increases rapidly. As a rule of thumb, remember that the more different items are involved, the longer
the execution time is. For example, the following table gives some short examples of some rather basic FlexibleSearch statements and the actual SQL queries
triggered:
FlexibleSearch statement
SELECT {pk}
FROM {Product}
SQL statement
SELECT
Description
This FlexibleSearch statement results in no big
item_t0.PK
FROM products item_t0
WHERE (item_t0.TypePkString
IN (
23087950835790560 , 23087950835774560 ,
23087950837855968 , 23087950837852464 ,
surprises. Basically,\ SAP Commerce translates the
type system related data into the matching SQL
data. Note that the actual database table to be
searched is products, and not product as you
might expect.
23087950837859216 , 23087950837848976 ,
23087950837843968 , 23087950835790306 ,
23087950835765569
)
)
SELECT {description}
FROM {Product}
SELECT
lp_t0.p_description
FROM productslp lp_t0
WHERE
Even though you run the FlexibleSearch on the
Product type, the SQL statement is run on the
productslp table instead of on the products
table. This is because the description attribute
(
is localized, and localized attributes for a type are
(lp_t0.LANGPK=?)
stored in an individual database table.
)
AND
(lp_t0.ITEMTYPEPK
IN (
23087950835790560 , 23087950835774560 ,
23087950837855968 , 23087950837852464 ,
23087950837859216 , 23087950837848976 ,
23087950837843968 , 23087950835790306 ,
23087950835765569
)
)
SELECT {code}, {description}
FROM {Product}
SELECT
item_t0.Code ,
lp_t0.p_description
FROM
The seemingly simple example, SELECT {code},
{description} FROM {Product}, requires a
products item_t0
JOIN over the products table and the localized
JOIN productslp lp_t0
tables of the products table ( products_lp ) in
ON item_t0.PK = lp_t0.ITEMPK
order to get ahold of the localizations of the
AND lp_t0.LANGPK=?
description attribute as well. Whenever you run
WHERE
FlexibleSearch statements on localized and non-
(
localized attributes of the same type, a JOIN is
item_t0.TypePkString
necessary.
IN (
23087950835790560 , 23087950835774560 ,
23087950837855968 , 23087950837852464 ,
23087950837859216 , 23087950837848976 ,
23087950837843968 , 23087950835790306 ,
23087950835765569
)
)
2. Search results may differ over time:
When a FlexibleSearch query is run for the rst time, the search results correspond to the dataset in the database by execution time. As every navigation through
paged search results runs a new database query, the FlexibleSearch statement always receives a list of search results which correspond to the point of time when the
statement is executed. This means, however, that the list of search results does not necessarily match the list of search results which were found when the
FlexibleSearch query was initially executed. Items referenced in the initial query may have been updated, created, or removed in the meantime.
This is custom documentation. For more information, please visit the SAP Help Portal
48
5/27/2022
3. ORDER BY required:
The order in which unordered database search results are returned may differ on every database statement execution, depending on the database implementation.
By consequence, an unordered FlexibleSearch query might receive different search results on every navigation through paged search results. To avoid seemingly
random search results, using paged search results requires an ORDER BY clause in the FlexibleSearch. Note, that ordering the paged search results does not solve
the issue with search results differing over time.
Testing FlexibleSearch Queries Using the SAP Commerce Administration Console
The SAP Commerce offers a tool to test FlexibleSearch queries. To access and test queries, follow the steps below:
1. Open the SAP Commerce Administration Console.
2. Go to the Console tab and select the FlexibleSearch option.
3. The FlexibleSearch page displays. If you do not have any queries ready, you can use Query samples located in the sidebar.
4. Enter the query in FlexibleSearch query or Direct SQL query eld.
5. Click the Execute button.
For more information, see hybris Administration Console - End User Guide
Advanced: Specifying a Minimum Time to Live for Cached FlexibleSearch Results
The system enables you to specify a minimum time to live for FlexibleSearch results. For more information, see hybris Platform Cache, section Advanced: Specifying a
Minimum Time to Live for Cached FlexibleSearch Results.
Restrictions
Restrictions are rules obeyed by FlexibleSearch which allow to limit search results depending on which type is searched and which user is currently logged in.
This happens transparently and does not require any code adjustment on business layer.
A restriction is basically just a fragment of the WHERE clause of a FlexibleSearch statement - that is, a restriction adds search conditions. SAP Commerce automatically
adds them to the WHERE clauses of all applicable FlexibleSearch statements and thereby restricts the number of search results of these statements due to these additional
search conditions.
For example:
FlexibleSearch Statement
Restriction Statement
Effective FlexibleSearch Statement
This is custom documentation. For more information, please visit the SAP Help Portal
49
5/27/2022
FlexibleSearch Statement
Restriction Statement
SELECT {p:pk} FROM {Product AS p}
Effective FlexibleSearch Statement
{p:description} NOT NULL
WHERE {p:code} LIKE '%test%'
SELECT {p:pk} FROM {Product AS p}
WHERE {p:code} LIKE '%test%'
AND {p:description} NOT NULL
A restriction always applies to a speci ed type and a speci ed User or UserGroup. If the type has subtypes, then the subtypes are affected by the restriction as well. If the
restriction applies to a UserGroup, then it affects all members of that UserGroup, including other UserGroups (whose members are affected by the restriction as well).
Scope of Restrictions
The effect of restrictions is transparent, no interaction is necessary. Whenever a restriction is active and applies to the combination of restricted type and user, the search
results are limited.
Unlike type access rights (which are only effective within the Hybris Management Console), restrictions apply to FlexibleSearch results throughout SAP Commerce. In other
words, restrictions affect FlexibleSearch results in the Hybris Management Console, in the SAP and in an SAP Commerce-based web application. Type access rights only
affect the Hybris Management Console.
Since restrictions work on FlexibleSearch queries only, restrictions do not affect the following use cases:
External search engines like Lucene
Search results supplied by third-party search engines are not affected by restrictions. To get third-party search engine search results affected by restrictions, you will
need to lter these search results by running a FlexibleSearch statement over them.
Item.getProperty(), LocalizableItem.getLocalizedProperty() fetches item references directly via PK - any stored item will be returned no matter if it would have been
ltered by a currently active restriction
SAP Commerce includes a mechanism that allows using restrictions for cron jobs. For details, please refer to cronjob - Technical Guide.
Using Parameters in Restrictions
Often it will do to specify restrictions having literal query texts like
IS NOT NULL
or {hidden}=1.
But sometimes it may also be required to specify a restriction which relies upon a session bound parameters instead of a xed literal value. To do so just use the ?session
FlexibleSearch parameter which is available inside every query.
Now we're able to write restrictions like {user} = ?session.user or {country} IN ( ?session.countries) which gives us the freedom to lter differently depending upon which
session context settings have been made.
 Caution
When refering to custom session context attribute (like countries above) make sure that the session context does contain this attribute. Otherwise any attempt to run a
query which is affected by the restriction will throw a FlexibleSearch error!
Disabling Restrictions
For development, testing and debugging purposes, it may prove useful to disable restrictions as they falsify FlexibleSearchService query results.
Assigning the Session to an Admin User
By convention, restrictions do not apply to admin users (that is, users who are members of the admingroup user group). This means that a session assigned to a member of
the admingroup user group is not affected by restrictions. This setting is in effect as long as the session is assigned to an admin user and applies to all restrictions.
 Note
Using Filters
Assigning the session to an admin user has the side effect of granting the session access to every CatalogVersion in SAP Commerce. The default user assigned to a
session (anonymous) requires that CatalogVersions be set for the session explicitly. To make sure that CatalogVersions are set for non-admin user sessions, you need to
integrate lters in your Web application. You need to use the Commerce Platform lter chain. Use it to add proper lter for catalog version activation into the lter chain.
Read hybris Platform Filters for more details.
Find an example on how to assign the session to the admin user below:
...
import de.hybris.platform.servicelayer.user.UserService;
...
@Autowired
private UserService userService;
...
This is custom documentation. For more information, please visit the SAP Help Portal
50
5/27/2022
userService.setCurrentUser(userService.getAdminUser())
...
The following code snippet shows how to get Products for a category available for admin user. The important part here is the fact that setting admin user in the session as
well getting products is executed in local view by using sessionService.executeInLocalView.
...
import de.hybris.platform.product.ProductService;
import de.hybris.platform.servicelayer.session.SessionExecutionBody;
import de.hybris.platform.servicelayer.session.SessionService;
import de.hybris.platform.servicelayer.user.UserService;
...
@Autowired
private SessionService sessionService;
@Autowired
private UserService userService;
@Autowired
private ProductService productService;
...
public List<ProductModel> getProductsByCategory()
{
return (List<ProductModel>) sessionService.executeInLocalView(new SessionExecutionBody()
{
@Override
public List<ProductModel> execute()
{
userService.setCurrentUser(userService.getAdminUser());
return productService.getProductsForCategory(getSomeCategory());
}
});
}
private CategoryModel getSomeCategory()
{
...
return someCategoryHere;
}
Enabling or Disabling Search Restrictions
Find below an example of how to enable and disable a search restriction:
...
import de.hybris.platform.search.restriction.SearchRestrictionService;
...
// Disable search restrictions
searchRestrictionService.disableSearchRestrictions();
// some query goes here
// Enable search restrictions
searchRestrictionService.enableSearchRestrictions();
// some query goes here
Creating Restrictions
A restriction is represented by a SearchRestriction class instance, which has the following mandatory attributes:
SearchRestriction Attribute
Allowed Value
Description
active
java.lang.Boolean
Speci es whether the SearchRestriction is enabled (true) or
disabled (false. Defaults to true.
code
java.lang.String
The identi er for the restriction. Must be unique throughout
all SearchRestriction type instances.
principal
Principal
The user or user group to whom the restriction applies.
query
java.lang.String
The query of the SearchRestriction, that is, a WHERE clause
of a FlexibleSearch statement that narrows down a
FlexibleSearch statement.
restrictedType
ComposedType
The type on which FlexibleSearch queries are to be
restricted when executed with the speci ed principal.
generate
java.lang.Boolean
De nes whether the build process should generate a jalo
code for this type system element. SearchRestriction
extends TypeManagerManaged that has the non-optional
generate eld.
Creating a restriction is possible in two ways: via the SAP Commerce API and via the Hybris Management Console.
Creating Restrictions via the SAP Commerce API
To create a restriction we need to use model service to create a new SearchRestrictionModel instance and then populate it with desired attributes, for example:
This is custom documentation. For more information, please visit the SAP Help Portal
51
5/27/2022
final ComposedTypeModel restrictedType = typeService.getComposedTypeForClass(LanguageModel.class);
final PrincipalModel principal = userService.getUserForUID("ahertz");
final SearchRestrictionModel searchRestriction = modelService.create(SearchRestrictionModel.class);
searchRestriction.setCode("some code");
searchRestriction.setActive(Boolean.TRUE);
searchRestriction.setQuery("{active} IS TRUE");
searchRestriction.setRestrictedType(restrictedType);
searchRestriction.setPrincipal(principal);
searchRestriction.setGenerate(Boolean.TRUE);
modelService.save(searchRestriction);
Creating Restrictions via the Hybris Management Console
See How To Create Restrictions Using hybris Management Console - Tutorial document for details.
Creating Restrictions via the ImpEx Extension
The following sample code shows how to create restrictions via an Impex-compliant CSV le:
INSERT_UPDATE SearchRestriction;code[unique=true];name[lang=de];name[lang=en];query;principal(UID);restrictedType(code);active;generat
;Frontend_Navigationelement;Navigation;Navigation;{active} IS TRUE;test_user;Language;true;true
Related Information
impex Extension - Technical Guide
Visibility Mechanisms (Checklist)
cronjob - Technical Guide
How To Create Restrictions Using hybris Management Console - Tutorial
Creating Restrictions Using Hybris Management Console
You can easily create restrictions for FlexibleSearch in the HMC.
Procedure
1. Log in to Hybris Management Console using an account with sufficient rights to create restrictions.
2. Go to System Personalization .
3. Right-click on Personalization in the explorer tree and select Create Personalization Rule.
4. Go to the Properties tab and enter a name for the new restriction into the Identi er eld.
5. Enter a restriction query into the Filter eld.
This is custom documentation. For more information, please visit the SAP Help Portal
52
5/27/2022
6. Select a type from Restricted Type menu.
7. Select a user or a user group for the restriction to be effective on from the Apply on menu.
8. Click Create to save the new restriction.
FlexibleSearch Samples
This document discusses a number of FlexibleSearch samples. As the FlexibleSearch is a key component of SAP Commerce, reading this document is recommended for all
developers.
This document does not discuss the FlexibleSearch in general, please refer to FlexibleSearch for general information on the FlexibleSearch.
Basic SELECT Statements
This section discusses FlexibleSearch statements with one single SELECT operator. Some of these samples overlap in terms of operators, this is hard to avoid for such a
subject.
SELECT Statements with Negation
The following FlexibleSearch statements are samples for using the negation operator NOT.
Getting all Products whose code is not empty
The following FlexibleSearch statement returns Primary Keys (PK) of every Product whose code attribute is different from null. Be aware that in SQL syntax the
empty string "" is not considered to be null. In other words: the following FlexibleSearch statement nds Products whose code is set to "".
SELECT {p.pk} FROM {Product AS p} WHERE {p.code} IS NOT NULL
Getting all Categories whose code does not contain a certain string
This is custom documentation. For more information, please visit the SAP Help Portal
53
5/27/2022
The following FlexibleSearch statement returns the PKs of every Category whose code attribute does not contain the string test.
SELECT {c:pk} FROM {Category AS c} WHERE {c:code} IS NOT LIKE '%test%'
SELECT Statements with Several Return Columns
The arguments passed for the SELECT operator specify the columns from the database that are to be returned by the FlexibleSearch query.
Returning every database column of every Category
The following FlexibleSearch statement returns every database column of every Category in SAP Commerce. The list of returned database columns could be
something along the lines of: hjmpts, modi edts, createdts, typepkstring, pk, ownerpkstring, aclts, propts, p_showemptyattributes, p_normal, p_thumbnails,
p_revision, p_code, p_data_sheet, p_logo, p_catalogversion, p_picture, p_detail, p_catalog, p_others, p_order, p_thumbnail, and p_externalid.
SELECT * FROM {Category}
Getting the point of time when a Category was last modi ed, Category code and PK
The following FlexibleSearch statement returns three database columns of every Category in SAP Commerce. Note that the code attribute is enclosed by curly
braces.
SELECT {cat:modifiedtime}, {cat:code}, {cat:pk} FROM {Category AS cat}
SELECT Statements Over Several Attributes
A FlexibleSearch statement allows narrowing down the list of search results by specifying several attributes in a search condition. A SAP Commerce item must match the
search condition in the respective attribute to become included in the search result list. For example, if the FlexibleSearch statement queries for the code and the name
attribute, the list of search results contains only items that have a matching value in both the code and the name attribute.
Getting all Products whose code or name contains a certain string
The following FlexibleSearch returns the PKs of all Products whose code attribute or name attribute contains a string that ends with myProduct.
SELECT {p:PK}
FROM {Product AS p}
WHERE {p:code} LIKE '%myProduct'
OR {p:name} LIKE '%myProduct'
ORDER BY {p:code} ASC
The percent sign (%) works as a wildcard character:
a% nds all strings that start with an a,
%a nds all strings that end with an a,
%a% nds all strings that contain an a.
By introducing a parameter (?name in the following FlexibleSearch query) into the query, you can search for any search string:
SELECT {p:PK}
FROM {Product AS p}
WHERE {p:code} LIKE ?name
OR {p:name} LIKE ?name
ORDER BY {p:code} ASC
Be aware that the search condition WHERE LIKE ?name only nds products whose name attribute matches the value of the ?name parameter exactly. To
nd Products whose name attribute contains the value of the ?name parameter only partially, you need to use wildcard characters, as in WHERE LIKE
CONCAT('%', CONCAT(?name, '%')) or enclosing parameter by wildcard characters like:
...LIKE ?name; query.addQueryParameter("name", "%h%") . Both solutions are SQL-injection safe.
SELECT Statements Over Several Languages
SAP Commerce allows for attributes to be localized, that is, to have an individual value for each language in SAP Commerce. By specifying the language code enclosed by
square brackets ([ and ], respectively) after the attribute name, such as {description[de]}. Not specifying a language code for a localized attribute causes SAP
Commerce to use the default language for the current session.
Getting all Products with an empty name in the current SAP Commerce language
The following FlexibleSearch query returns the PKs of all Products whose name attribute is not set (IS NULL). The name attribute is localized, but the FlexibleSearch
query does not specify a language explicitly, therefore the FlexibleSearch defaults to the current session language.
SELECT {p:PK}
FROM {Product AS p}
WHERE {p:name} IS NULL
Getting all Products with an empty name in German or an empty description in English
The following FlexibleSearch query returns the PKs of all Products and whose...
name attribute is not set for the German language (IS NULL) or
This is custom documentation. For more information, please visit the SAP Help Portal
54
5/27/2022
description attribute is not set for the English language (IS NULL).
Both the name attribute and the description attributes are localized. The FlexibleSearch query speci es the language explicitly (via de and en, respectively). If no language is
speci ed, the FlexibleSearch would default to the current session language.
SELECT {p:PK}
FROM {Product AS p}
WHERE {p:name[de]} IS NULL
OR {p:description[en]} IS NULL
Searching several languages at once
By specifying different language codes, you can search localized attributes in various languages at a time. The following FlexibleSearch statement searches both the
English and German values of the description attribute:
SELECT {p:PK}
FROM {Product AS p}
WHERE {p:description[en]:o} LIKE '%text%'
OR {p:description[de]:o} LIKE '%text%'
Here, :o (outer join) parameter is used to include matches with missing rows in the ProductsLP table (=. the table that holds localized products) as well. Otherwise ,
the query would only return products with an existing row in ProductsLP table, because it would only use JOIN.
 Tip
Add OR Clause to Search Additional Attributes or Languages
To search another language, add the attribute to be searched with an explicit speci cation of the language to be searched to the WHERE clause via an OR clause. For
example, the following FlexibleSearch statement searches the description attribute of the Product in the three languages English, German, and French (en, de, and fr,
respectively) and the name attribute in German:
SELECT {p:PK}
FROM {Product AS p}
WHERE {p:description[en]:o} LIKE '%text%'
OR {p:description[de]:o} LIKE '%text%'
OR {p:name[de]:o} LIKE '%text%'
OR {p:description[fr]:o} LIKE '%text%'
It is also possible to replace the hard-coded search string with a parameter. Please refer to the SELECT statements with parameters section below for details.
SELECT Statements with Parameters
A parameter in a FlexibleSearch query allows inserting varying search patterns. This is a common eld of use for applications where one single query is intended to be used
for various searches, such as:
Search elds in the store frontend.
Search elds in the Hybris Management Console.
Item retrieval in the application business code.
Using one parameter in a FlexibleSearch statement
The following FlexibleSearch statement queries the description attribute in three SAP Commerce languages (en, de, fr) for one single parameter, ?param. In other
words, the FlexibleSearch nds all Product instances whose description in English, German, or French contains the search pattern speci ed by ?param.
SELECT {p:PK}
FROM {Product AS p}
WHERE {p:description[en]:o} LIKE ?param
OR {p:description[de]:o} LIKE ?param
OR {p:description[fr]:o} LIKE ?param
Note, that there are :o characters in WHERE clause. They are used to force the related table to be outer-joined (in case of localized properties the xxxLP table).
Using two parameters in a FlexibleSearch statement
Getting every Product that is in at least one of two Categories:
SELECT {cpr:target}
FROM {CategoryProductRelation AS cpr}
WHERE {cpr:source} LIKE ?param1
OR {cpr:source} LIKE ?param2
Getting every Product that was changed between two dates:
SELECT {pk}
FROM {Product}
WHERE {modifiedtime} >= ?startDate
AND {modifiedtime} <= ?endDate
SELECT Statements with Concatenation
This is custom documentation. For more information, please visit the SAP Help Portal
55
5/27/2022
The FlexibleSearch feature allows concatenating strings within a statement. Be aware that each CONCAT operator call allows only two parameters. To concatenate more
than two parameters, you need to run more than one CONCAT operator calls.
Enclosing a search string by percent signs %
The following FlexibleSearch statement gives an example on the CONCAT operator by concatenating the leading % character with the concatenation of myProduct
and the % character for a total of %myProduct%:
SELECT {p:PK}
FROM {Product AS p}
WHERE {p:description[de]}
LIKE
CONCAT(
'%',
CONCAT(
'myProduct',
'%'
)
)
OR {p:description[en]}
LIKE
CONCAT(
'%',
CONCAT(
'myProduct',
'%'
)
)
ORDER BY {p:code} ASC
This function is useful in combination with parameters, as in the following FlexibleSearch statement:
SELECT {p:PK}
FROM {Product AS p}
WHERE {p:description[de]} LIKE
CONCAT(
'%',
CONCAT(
?param,
'%'
)
)
OR {p:description[en]} LIKE
CONCAT(
'%',
CONCAT(
?param,
'%'
)
)
ORDER BY {p:code}
SELECT Statements with DISTINCT Operator
The DISTINCT operator makes sure that duplicate results are returned only once. Duplicate return results may occur from sub-selects, JOIN clauses or from identical
parameters, for example.
Finding every Product that is in at least one of two given Categories
The following FlexibleSearch statement returns every Product that is assigned to at least one of the two Categories provided by the two parameters ?param1 and ?
param2. The DISTINCT operator ensures that every Product is returned only once even if it were assigned to both Categories.
SELECT DISTINCT {cpr:target}
FROM {CategoryProductRelation AS cpr}
WHERE {cpr:source} LIKE ?param1
OR {cpr:source} LIKE ?param2
SELECT Statements with GROUP BY Operator
Getting every Product which has been ordered, grouped by the Product
SELECT {oe:product}
FROM {OrderEntry AS oe}
GROUP BY {oe:product}
Subselects
A subselect is a SELECT statement within a SELECT statement. Via a subselect, a SELECT statement can affect (narrow down or expand, for example) a search result list.
The basic syntax looks as follows:
SELECT *
FROM ${type}
WHERE
{{
SELECT *
FROM ${other_type}
This is custom documentation. For more information, please visit the SAP Help Portal
56
5/27/2022
WHERE ${subselect_search_condition}
}}
 Note
Subselects in FROM clause of the query are also allowed (the example above presents subselect in the WHERE clause of the query). See Subselect with Parameters
section below for more details.
Subselect Over Several Types
Getting every Product that has a directly or indirectly assigned PriceRow
The following FlexibleSearch statement lists every Product that:
has at least one DiscountRow directly assigned to it (subselect 1) or
is assigned to a ProductDiscountGroup that thas a DiscountRow assigned to it (subselect 2)
SELECT DISTINCT {p:PK}, {p:name}, {p:code}
FROM {Product AS p}
WHERE {p:PK} IN
(
{{
-- subselect 1
SELECT {dr:product}
FROM {DiscountRow AS dr}
}}
)
OR {p:PK} IN
(
{{
-- subselect 2
SELECT {prod:PK}
FROM
{
Product AS prod
LEFT JOIN DiscountRow AS dr
ON {prod:Europe1PriceFactory_PDG} = {dr:pg}
}
WHERE {prod:Europe1PriceFactory_PDG} IS NOT NULL }}
)
ORDER BY {p:name} ASC, {p:code} ASC
Getting every Product that is in at least 3 Categories
The following FlexibleSearch statement returns every Product that is in more than three Categories (speci ed by the WHERE howmany > 3 clause in subselect 1).
The subselect 2 returns the number of categories a Product is in (via searching the CategoryProductRelation). The subselect 1 returns only those products which are
in more than three Categories (WHERE howmany >3).
SELECT {p:PK}
FROM {Product AS p}
WHERE {p:PK} IN
(
-- subselect 1
SELECT prod
FROM
(
{{
-- subselect 2
SELECT {cpr:target} AS prod, count({cpr:target}) AS howmany
FROM {CategoryProductRelation AS cpr}
GROUP BY {cpr:target}
}}
)
temptable
WHERE howmany > 3
)
ORDER BY {p:name} ASC, {p:code} ASC
 Note
Add a Parameter for Flexibility
By replacing the hard-coded 3 with a parameter, you could use the statement to nd every Product that is in a speci ed number of categories, such as:
SELECT {p:PK}
FROM {Product AS p}
WHERE {p:PK} IN
(
-- subselect 1
SELECT prod
FROM
(
{{
-- subselect 2
SELECT {cpr:target} AS prod, count({cpr:target}) AS howmany
FROM {CategoryProductRelation AS cpr}
GROUP BY {cpr:target}
}}
)
temptable
WHERE howmany > ?number
This is custom documentation. For more information, please visit the SAP Help Portal
57
5/27/2022
)
ORDER BY {p:name} ASC, {p:code} ASC
Please also refer to the Subselect with Parameters section below for additional information.
Subselect with Parameters
Getting all Products ordered on or after a certain date
The following FlexibleSearch statement returns every Product that was ordered on or after a certain date. Via subselect 2, the FlexibleSearch statement retrieves
every Order that was created on or after the value speci ed by the ?date parameter. Of these search results, subselect 1 retrieves the OrderEntries that belong to
these Orders. The outermost SELECT statement gets the Products referred by the OrderEntries.
SELECT {p:PK}
FROM {Product AS p}
WHERE {p:PK} IN
(
{{
-- subselect 1
SELECT DISTINCT {oe:product}
FROM {OrderEntry AS oe}
WHERE {oe:order} IN
(
{{
-- subselect 2
SELECT {o:PK}
FROM {Order AS o}
WHERE {o:date} >= ?date
}}
)
}}
)
Getting every Product without a PriceRow in a speci ed Currency
The following FlexibleSearch statement returns every Product that does not have a PriceRow assigned for the speci ed Currency. The subselect returns every
PriceRow for the speci ed currency. This search result is then negated via the outer FlexibleSearch statement, which returns every Product that is not included in the
search results that are returned by the subselect.
SELECT {p:PK}
FROM {Product AS p}
WHERE {p:PK} NOT IN
(
{{
-- subselect
SELECT {pr:product}
FROM {PriceRow AS pr}
WHERE {pr:currency} = ?currency
}}
)
ORDER BY {p:name} ASC, {p:code} ASC
Reporting query with subselect in FROM clause and SQL aggregate functions.
This query calculates average Order value and average Order unit count within speci ed date range.
Result of this query is a pair of numeric values. The rst one is the average Order value, and the second one is the average order unit count.
The term unit count of the order means the sum of quantities of the order entries. For example if an order consists of:
1 red T-shirt
1 blue T-shirt
2 yellow T-shirt
Then the order unit count for this order is 4.
SELECT AVG(torderentries.totprice), AVG(torderentries.totquantity)
FROM (
{{
SELECT SUM({totalPrice}) AS totprice, SUM({quantity}) AS totquantity FROM {OrderEntry}
WHERE {creationtime} >= ?startDate AND {creationtime} < ?endDate GROUP BY {order}
}}
) AS torderentries
Combined SELECT Statements with UNION Operator
The following FlexibleSearch statement uses the UNION operator to retrieve the set of results for two SELECT statements:
SELECT x.PK
FROM
(
{{SELECT {PK} as PK FROM {Chapter}
WHERE {Chapter.PUBLICATION} LIKE 6587084167216798848
}}
UNION ALL
{{
This is custom documentation. For more information, please visit the SAP Help Portal
58
5/27/2022
SELECT {PK} as PK FROM {Page}
WHERE {Page.PUBLICATION} LIKE 6587084167216798848
}}) x
FlexibleSearch Tips and Tricks
You can use the FlexibleSearch to build advanced queries for reports, get information from collection attributes, use and format dates, or use conditional parts of the query.
Flexible Search and Collections
Let's say you have a subtype of Order that holds a collection of VoucherCard items. You wish to get all VoucherCards which are assigned to a particular order, and the prices
assigned to the VoucherCards.
As long as the collection element type has a reference to the item that holds the collection, all is simple:
SELECT {vc.PK}, {vc.price}
FROM
{
Order AS o JOIN VoucherCard AS vc
ON {vc.order}= {o.pk}
}
WHERE {o.PK} = ?order
Things get more complicated if the reference between element and holder is missing. You can use some workaround based on the fact that a collection attribute is stored as
a list of PK s:
SELECT {dm.code}, {pm.code}
FROM
{
DeliveryMode AS dm JOIN PaymentMode AS pm
ON {dm.supportedPaymentModeInternal} LIKE CONCAT( '%', CONCAT( {pm.PK} , '%' ) )
}
JOIN Clauses
In FlexibleSearch queries, only two kinds of JOIN clauses are available:
LEFT JOIN
JOIN
These clauses can be useful if you wish to select items that are connected to other items via a relation, for example:
SELECT {p:PK}, {c:code} FROM
{
Product as p JOIN CategoryProductRelation as rel
ON {p:PK} = {rel:target}
JOIN Category AS c
ON {rel:source} = {c:PK}
}
UNION Clauses
UNION clauses allow to unite the results of different queries. Here is a simple example of how to get all pages and chapters of a publication. ?pk is a query parameter, for
which a value must be speci ed at run time.
SELECT uniontable.PK, uniontable.CODE FROM
(
{{
SELECT {c:PK} as PK, {c:code} AS CODE FROM {Chapter AS c}
WHERE {c:PUBLICATION} LIKE ?pk
}}
UNION ALL
{{
SELECT {p:PK} as PK, {p:code} AS CODE FROM {Page AS p}
WHERE {p:PUBLICATION} LIKE ?pk
}}
) uniontable
Using Temporary Tables
When you use temporary tables, you will need to use a slightly different syntax to retrieve values from a temporary table. Instead of the FlexibleSearch syntax
(INNERTABLE:PK), you have to use the native SQL syntax (INNERTABLE.PK), such as:
This is custom documentation. For more information, please visit the SAP Help Portal
59
5/27/2022
SELECT INNERTABLE.PK, INNERTABLE.CatCode FROM
(
{{
SELECT {p:PK} AS PK, {c:code} AS CatCode FROM
{
Product as p JOIN CategoryProductRelation as rel
ON {p:PK} = {rel:target}
JOIN Category AS c
ON {rel:source} = {c:PK}
}
}}
) INNERTABLE
Conditional CASE Statements
If you create a complex query and you want to return different results of an attribute based on some condition, try the CASE statement.
See an example of getting all categories names, codes and number of super categories. If category does not have any subcategories mark it as root category, otherwise mar
it as normal category.
SELECT {c:name[en]} AS Name, {c:code} AS Code,
(
CASE
WHEN COUNT(DISTINCT{superCategory:PK}) <= 0
THEN 'root category'
ELSE 'normal category'
END
) as TYPE,
COUNT(DISTINCT{superCategory:PK}) AS SuperCategories
FROM
{
Category as c LEFT JOIN CategoryCategoryRelation as rel
ON {c:PK} = {rel:target}
LEFT JOIN Category AS superCategory
ON {rel:source} = {superCategory:PK}
}
GROUP BY {c:PK}, {c:code}, {c:name[en]}
NAME
CODE
TYPE
SUPERCATEGORIES
AMD
HW2120
normal category
2
AMD
HW2120
normal category
2
ATI
HW2320
normal category
1
ATI
HW2320
normal category
1
Accessories
accessories
root category
0
Accessories
accessories
root category
0
Anti-Virus Software
antivirus
normal category
1
Apparel
apparel
root category
0
Apparel
apparel
root category
0
You can also put SELECT statements into CASE statements, as in this little more complicated query snippet below. The query basically counts super categories for each
category and sub categories only for the root category. It may seem that such a query would never be used but it sometimes is the only solution for a report table lling
query - a table that also is responsible to aggregate and sort results.
SELECT {c:name[en]} AS Name, {c:code} AS Code,
(
CASE
WHEN COUNT(DISTINCT{superCategory:PK}) <= 0
THEN 'root category'
ELSE 'normal category'
END
) as TYPE,
(
CASE
WHEN ( COUNT(DISTINCT{superCategory:PK}) <= 0 )
THEN
(
{{
SELECT COUNT({innerC:PK}) FROM
{
Category as innerC LEFT JOIN CategoryCategoryRelation as innerRel
ON {innerC:PK} = {innerRel:target}
}
WHERE {innerRel:source} = {c:pk}
}}
)
ELSE 0
END
) as RootSubCategories,
COUNT(DISTINCT{superCategory:PK}) AS SuperCategories
This is custom documentation. For more information, please visit the SAP Help Portal
60
5/27/2022
FROM
{
Category as c LEFT JOIN CategoryCategoryRelation as rel
ON {c:PK} = {rel:target}
LEFT JOIN Category AS superCategory
ON {rel:source} = {superCategory:PK}
}
GROUP BY {c:PK}, {c:code}, {c:name[en]}
NAME
CODE
TYPE
ROOTSUBCATEGORIES
SUPERCATEGORIES
Accessories
accessories
root category
0
0
Accessories
accessories
root category
0
0
Anti-Virus Software
antivirus
normal category
0
1
CPU
cpu
normal category
0
1
Content blocks
contentblocks
root category
3
0
Content blocks
contentblocks
root category
3
0
Digital photography
photography
normal category
0
1
Electronical Goods
electronics
root category
2
0
Hardware
hardware
normal category
0
1
Mainboards
boards
normal category
0
1
Memory
memory
normal category
0
1
Men's shoes
CL2100
normal category
0
1
Men's shoes
CL2100
normal category
0
1
Operating Systems
operating
normal category
0
1
Date Formatting
If you use dates in SQL, it is very likely that you would need to compare only parts of the date - for example, you would need to consider only months, dates, hours, but skip
seconds and milliseconds. Nearly in every report you need to group your results by some date - months, hours and so on. Here is how you do that on MySQL and Oracle.
Oracle
SELECT to_char({o:date},'mm/yyyy'), COUNT(DISTINCT{o:PK})
FROM {Order AS o}
GROUP BY to_char({o:date},'mm/yyyy')
MySQL
SELECT DATE_FORMAT({o:date},'%M/%Y'), COUNT(DISTINCT{o:PK})
FROM {Order AS o}
GROUP BY DATE_FORMAT({o:date},'%M/%Y')
String Formatting
In addition to date-speci c operators, database system also offer String-speci c operators.
MySQL Functions
Function
Description
ASCII()
Return numeric value of left-most character
BIN()
Return a string representation of the argument
BIT_LENGTH()
Return length of argument in bits
CHAR_LENGTH()
Return number of characters in argument
CHAR()
Return the character for each integer passed
CHARACTER_LENGTH()
A synonym for CHAR_LENGTH()
CONCAT_WS()
Return concatenate with separator
This is custom documentation. For more information, please visit the SAP Help Portal
61
5/27/2022
Function
Description
CONCAT()
Return concatenated string
ELT()
Return string at index number
EXPORT_SET()
Return a string such that for every bit set in the value bits, you get an on string and for every
unset bit, you get an off string
FIELD()
Return the index (position) of the rst argument in the subsequent arguments
FIND_IN_SET()
Return the index position of the rst argument within the second argument
FORMAT()
Return a number formatted to speci ed number of decimal places
HEX()
Return a hexadecimal representation of a decimal or string value
INSERT()
Insert a substring at the speci ed position up to the speci ed number of characters
INSTR()
Return the index of the rst occurrence of substring
LCASE()
Synonym for LOWER()
LEFT()
Return the leftmost number of characters as speci ed
LENGTH()
Return the length of a string in bytes
LIKE
Simple pattern matching
LOAD_FILE()
Load the named le
LOCATE()
Return the position of the rst occurrence of substring
LOWER()
Return the argument in lowercase
LPAD()
Return the string argument, left-padded with the speci ed string
LTRIM()
Remove leading spaces
MAKE_SET()
Return a set of comma-separated strings that have the corresponding bit in bits set
MATCH
Perform full-text search
MID()
Return a substring starting from the speci ed position
NOT LIKE
Negation of simple pattern matching
NOT REGEXP
Negation of REGEXP
OCTET_LENGTH()
A synonym for LENGTH()
ORD()
Return character code for leftmost character of the argument
POSITION()
A synonym for LOCATE()
QUOTE()
Escape the argument for use in an SQL statement
REGEXP
Pattern matching using regular expressions
REPEAT()
Repeat a string the speci ed number of times
REPLACE()
Replace occurrences of a speci ed string
REVERSE()
Reverse the characters in a string
RIGHT()
Return the speci ed rightmost number of characters
RLIKE
Synonym for REGEXP
RPAD()
Append string the speci ed number of times
RTRIM()
Remove trailing spaces
SOUNDEX()
Return a soundex string
SOUNDS LIKE(v4.1.0)
Compare sounds
SPACE()
Return a string of the speci ed number of spaces
STRCMP()
Compare two strings
SUBSTR()
Return the substring as speci ed
SUBSTRING_INDEX()
Return a substring from a string before the speci ed number of occurrences of the delimiter
SUBSTRING()
Return the substring as speci ed
TRIM()
Remove leading and trailing spaces
UCASE()
Synonym for UPPER()
UNHEX()(v4.1.2)
Convert each pair of hexadecimal digits to a character
This is custom documentation. For more information, please visit the SAP Help Portal
62
5/27/2022
Function
Description
UPPER()
Convert to uppercase
Oracle Functions
Function
De nition
ASCII
The ASCII function returns the decimal representation in the database character set of the
rst character of char.
CHR
The CHR function returns the character having the binary equivalent to n as a VARCHAR2
value in either the database character set.
COALESCE
The COALESCE function returns the rst non-null expr in the expression list. At least one
expr must not be the literal NULL. If all occurrences of expr evaluate to null, then the
function returns null.
CONCAT
The CONCAT function returns the concatenation of 2 strings. You can also use the ||
command for this.
CONVERT
The CONVERT function converts a string from one characterset to another. The datatype of
the returned value is VARCHAR2.
DUMP
The DUMP function returns a VARCHAR2 value containing the datatype code, length in
bytes, and internal representation of expr. The returned result is always in the database
character set.
INSTR
Returns the position of a String within a String. For more information see Oracle instr function
INITCAP
Transform String to init cap
INSTRB
Returns the position of a String within a String, expressed in bytes.
INSTRC
Returns the position of a String within a String, expressed in Unicode complete characters
INSTR2
Returns the position of a String within a String, expressed in UCS2 code points
INSTR4
Returns the position of a String within a String, expressed in UCS4 code points
LENGTH
The LENGTH functions returns the length of char. LENGTH calculates length using characters
as de ned by the input character set.
LENGTHB
Returns the length of a string, expressed in bytes.
LOWER
The LOWER function returns a string with all lower case characters.
LPAD
Add characters to the left of a string until a xed number is reached. If the last parameter is
not speci ed, spaces are added to the left.
LTRIM
LTRIM removed characters from the left of a string if they are equal to the speci ed string. If
the last parameter is not speci ed, spaces are removed from the left side.
REPLACE
The replace function replaces every occurrence of a search_string with a new string. If no
new string is speci ed, all occurrences of the search_string are removed.
REVERSE
Reverses the characters of a String.
RPAD
Add characters to the right of a string until a xed number is reached. If the last parameter
is not speci ed, spaces are added to the right.
RTRIM
RTRIM removed characters from the right of a string if they are equal to the speci ed string.
If the last parameter is not speci ed, spaces are removed from the right side.
SOUNDEX
SOUNDEX returns a character string containing the phonetic representation of char. This
function lets you compare words that are spelled differently, but sound alike in English.
SUBSTR
Returns a substring. For more information see Oracle substring
SUBSTRB
Returns a substring expressed in bytes instead of characters.
SUBSTRC
Returns a substring expressed in Unicode code points instead of characters.
SUBSTR2
Returns a substring using USC2 code points.
SUBSTR4
Returns a substring using USC4 code points.
TRANSLATE
TRANSLATE returns expr with all occurrences of each character in from_string replaced by
its corresponding character in to_string. Characters in expr that are not in from_string are
not replaced.
TRIM
The TRIM function trims speci ed characters from the left and/or right. If no characters are
speci ed, the left and right spaces are left out.
(pipes)
With pipes you can concatenate strings.
UPPER
Transform a string to all upper case characters.
This is custom documentation. For more information, please visit the SAP Help Portal
63
5/27/2022
Function
De nition
VSIZE
The VSIZE function returns the byte size of a String.
Boolean Parameters in Queries
Since not all databases recognize true as a query parameter, 0 and 1 should be used instead of false and true.
Creating Report De nitions Using the Hybris Management Console
A Report De nition allows you to create customized calculated result sets for users and is the SAP Commerce representation of a database view. You can rely on the full
power of SQL to specify your result sets.
Steps to create a Report De nition using the Hybris Management Console:
1. Log into the Hybris Management Console.
2. Click the System link.
3. Click the Report De nitions link in the navigation tree.
4. Click the New icon. In the resulting drop down list, click Report De nition.
This is custom documentation. For more information, please visit the SAP Help Portal
64
5/27/2022
5. Enter an Identi er for the Report De nition.
6. Enter a Query for the Report De nition.
7. Create the Report De nition by clicking the Create button.
This is custom documentation. For more information, please visit the SAP Help Portal
65
5/27/2022
Managing SavedQuery Items in the Hybris Management Console
TheHybris Management Console (HMC) allows pre-de ning custom search queries based on the FlexibleSearch query language.
Creating a SavedQuery
This section discusses how to create a SavedQuery via the Hybris Management Console.
1. Log into the Hybris Management Console.
2. Click on the System link.
3. Right-click on the Saved Queries entry, then click on Create Saved Query.
4. Enter an identi er for the SavedQuery into the Identi er eld (mySavedQuery in the screenshot).
This is custom documentation. For more information, please visit the SAP Help Portal
66
5/27/2022
5. Enter the query for the SavedQuery into the Query eld (SELECT {pk} FROM {Product} in the screenshot).
6. Select the type to be returned from the incremental search Result Type eld (Product in the screenshot as the FlexibleSearch query returns Product instances).
7. Create the SavedQuery by clicking on the Create button.
Using a SavedQuery
This section discusses how to use a SavedQuery via the Hybris Management Console.
1. Log into the Hybris Management Console.
2. Click on the Catalog link.
This is custom documentation. For more information, please visit the SAP Help Portal
67
5/27/2022
3. Click on the Products link.
4. Click on the blue Saved Queries button.
5. Select one of the SavedQueries from the menu (mySavedQuery in the screenshot).
6. Click on the Search button to run the SavedQuery.
Related Information
advancedsavedquery Extension - Technical Guide
hMC - End User Guide
Import params for SavedQueries
GenericSearch
While SAP FlexibleSearch offers a powerful search API to developers, some of them may prefer the GenericSearch API that is similar to Hibernate Criteria Queries.
Hibernate is a collection of related projects, enabling developers to utilize POJO-style domain models in their applications in ways extending well beyond Object and
Relational Mapping.
Introduction
This is custom documentation. For more information, please visit the SAP Help Portal
68
5/27/2022
Both the FlexibleSearchService and the GenericSearch API allow developers to construct and execute queries against the SAP Commerce database, by focusing on SAP
Commerce items rather than raw SQL. However, the way in which the queries are constructed is based on two completely different and complimentary approaches.
A FlexibleSearchService query is constructed by placing a FlexibleSearch query statement in a String, for example:
""SELECT {" + CategoryModel.PK + "} FROM {" + CategoryModel._TYPECODE + "} WHERE {" CategoryModel.ID "}=?id";
The ?id placeholder in the query is the place for a real condition parameter that is replaced during query execution.
In contrast to this, a query, for the GenericSearchService is constructed by combining instances of GenericField and GenericCondition to form GenericQuery. GenericQuery
is a Java-based object describing the search criteria, an example of which is shown below. Users of Hibernate ORM can see a close parallel between this approach and the
Hibernate's Criteria Queries.
final String categoryID = "Foo";
final GenericCondition idCondition = GenericCondition.equals(
new GenericSearchField(CategoryModel._TYPECODE, CategoryModel.ID ), categoryID);
final GenericConditionList gl = GenericCondition.createConditionList(idCondition);
final GenericQuery query = new GenericQuery(CategoryModel._TYPECODE, gl);
To execute the FlexibleSearch, use the FlexibleSearchService:
Collection result = flexibleSearchService.<CategoryModel> search("SELECT
{" + CategoryModel.PK + "} FROM {" + CategoryModel._TYPECODE + "}
WHERE {" CategoryModel.ID "}").getResult();
Likewise, to execute the GenericSearch, use the GenericSearchService:
Collection result = genericSearchService.search(query).getResult();
This document describes the latter approach, of performing GenericSearch calls by constructing GenericQuery instances. See FlexibleSearch for a detailed discussion on the
former. Additionally, see the hybris Platform Search Mechanisms document for an overview of all search mechanisms available in SAP Commerce.
GenericSearch
The GenericSearch is a search framework that allows you to easily search on items stored within the Commerce Platform. Its functionality may be a bit limited, but on the
other hand, it is easy to understand and to handle. Although it technically uses the FlexibleSearch, it encapsulates the FlexibleSearch syntax and usage. The functionality of
the GenericSearch includes:
Searching of items as well as raw data elds
Unlimited number of conditions
Inner joins and outer joins between item types possible
Unlimited number of order by clauses
Subselects.
The GenericSearch is the tool of choice for a typical Find me all products sort of query that the real FlexibleSearchService would be an overkill to work with. If you do not
have extensive experience with the Commerce Platform, it is recommended to get familiar with the GenericSearch at rst and use it as a ladder to work yourself upwards to
the FlexibleSearch.
Before an actual GenericSearch statement is executed, it is run through a syntax checker. In other words, an incorrect statement is never executed. On top of that, you may
assign names to GenericSearch statements so you may save them in the database.
To run a GenericSearch statement, set up a query and then have the current session run that query. Technically, you create a GenericQuery object and add elds to it, that
contain the parts of your query that you want. An example for that:
// create a query to find products
GenericQuery query = new GenericQuery(ProductModel._TYPECODE);
// run the search
genericSearchService.search(query).getResult();
First, it creates a query that looks for products. Then it runs that query. Since the query is not limited in any way, it will nd all products within the platform. Now, re ne the
query:
// create a query to find products
final GenericQuery query = new GenericQuery(ProductModel._TYPECODE);
// create a new field as a container for the search results
// the field searches in ProductModel.NAME
// roughly translated into SQL terms: SELECT FROM ProductModel.Name
final GenericSearchField nameField = new GenericSearchField(ProductModel._TYPECODE, ProductModel.NAME);
// add a search condition to the field created above
// corresponds about to the SQL statement:
// WHERE (nameField) IS LIKE 'display'
final GenericCondition condition = GenericCondition.createConditionForValueComparison(nameField, Operator.LIKE, "display");
// Add that search condition to query
query.addCondition(condition);
This is custom documentation. For more information, please visit the SAP Help Portal
69
5/27/2022
// order by name - ascendingly
query.addOrderBy(new GenericSearchOrderBy(nameField, true));
// run the search
genericSearchService.search(query).getResult();
The listing above searches for all products with names containing the string display and presents them in an ascendant order by their name. The next listing extends that
even more:
// create a query to find products
final GenericQuery query = new GenericQuery(ProductModel._TYPECODE);
// create a new field as a container for the search results
// the field searches in ProductModel.NAME
// roughly translated into SQL terms: SELECT FROM ProductModel.Name
final GenericSearchField nameField = new GenericSearchField(ProductModel._TYPECODE, ProductModel.NAME);
// add a search condition to the field created above
// corresponds about to the SQL statement:
// where (nameField) IS LIKE 'display'
final GenericCondition condition = GenericCondition.createConditionForValueComparison(nameField, Operator.LIKE, "display");
// Add that search condition to query
query.addCondition(condition);
// order by name - ascendingly
query.addOrderBy(new GenericSearchOrderBy(nameField, true));
//create a join with all medias within the platform
GenericCondition joinCondition = GenericCondition.createJoinCondition(productMediaField, mediaField);
// add the join to the previous search so that only entries that
// match both searches are returned
query.addInnerJoin(joinCondition);
// run the search
genericSearchService.search(query).getResult();
This listing returns all products with names containing the string display that have a media assigned to them. If you wish to make use of the bookmark feature of the Hybris
Management Console (HMC), you need to assign a parameter to the search. The following listing shows how to do it:
// create a query to find products
final GenericQuery query = new GenericQuery(ProductModel._TYPECODE);
// create a new field as a container for the search results
// the field searches in ProductModel.NAME
// roughly translated into SQL terms: SELECT FROM ProductModel.Name
final GenericCondition condition = GenericCondition.createConditionForValueComparison(nameField, Operator.LIKE, "display", "myNameQual
// Add that search condition to query
query.addCondition(condition);
// order by name - ascendingly
query.addOrderBy(new GenericSearchOrderBy(nameField, true));
//create a join with all medias within Platform
final GenericCondition joinCondition = GenericCondition.createJoinCondition(productMediaField, mediaField);
// add the join to the previous search so that only entries that match both searches are returned
query.addInnerJoin(joinCondition);
// run the search
genericSearchService.search(query).getResult();
//reset the value
query.getCondition().setResettableValue("myNameQualifier", "floppy"); // (2)
// find products with "floppy" in a name
genericSearchService.search(query).getResult();
The main difference is marked by (1) - it is the name of a parameter that you may hand over, for example in the URL. In the (2) this parameter is set to a new value, in this
case String oppy. The search string to look for is then no longer display, but oppy. All other search parameters remain the same.
It is also possible to search for raw data instead of Item instances. To search for a code of a product, instead of for the Product itself, you should to do the following:
// the same code as above
// get only a code of products
final GenericSelectField codeField = GenericSelectField(ProductModel._TYPECODE, ProductModel.CODE, String.class);
query.addSelectField(codeField);
// find codes of products with "display" in their name
genericSearchService.search(query).getResult();
GenericSearch in Action
The most helpful resource for learning and seeing the GenericSearch in action is to take a look at the JUnit test for it in. The code sample below contains a commented
example taken from GenericSearchTest.java illustrating a simple GenericSearch:
GenericSearchTest.java
This is custom documentation. For more information, please visit the SAP Help Portal
70
5/27/2022
public void testGenericConditions() throws Exception{
//Create a GenericCondition
final GenericSearchField codeField = new GenericSearchField(ProductModel._TYPECODE, ProductModel.CODE);
GenericCondition condition = GenericCondition.createConditionForValueComparison(codeField, Operator.EQUAL, product1.getCode());
// Add this to a new GenericConditionList
final GenericConditionList conditionList = GenericCondition.createConditionList(condition);
// Create another GenericCondition and append it to this GenericConditionList
final GenericSearchField nameField = new GenericSearchField(ProductModel._TYPECODE, ProductModel.NAME);
conditionList.addToConditionList(GenericCondition.createConditionForValueComparison(nameField, Operator.STARTS_WITH,
"pRoduCt", /* upper */true));
// Create a GenericQuery
GenericQuery query = new GenericQuery(ProductModel._TYPECODE);
// Add the condition list to the GenericQuery
query.addCondition(conditionList);
// Also add two GenericSelectField to the GenericQuery
final GenericSelectField codeSelectField = new GenericSelectField(ProductModel._TYPECODE, ProductModel.CODE, String.class);
final GenericSelectField nameSelectField = new GenericSelectField(ProductModel._TYPECODE, ProductModel.NAME, String.class);
query.addSelectField(codeSelectField);
query.addSelectField(nameSelectField);
// Run the query
Collection result = genericSearchService.search(query, new StandardSearchContext(ctxDe)).getResult();
...
}
GenericSearchQuery as Container for GenericQuery
GenericSearchQuery is a container object that allows to con gure some additional search criteria and other options, like a user, for which the query is executed or
pagination. The base AbstractQuery class keeps common functionality for both GenericSearchQuery and FlexibleSearchQuery. One of the GenericSearchQuery
constructors provides a possibility to pass GenericQuery object as follows:
final GenericCondition idCondition = GenericCondition.equals(new GenericSearchField(CatalogModel._TYPECODE, CatalogModel.ID), TEST_CAT
final GenericConditionList gl = GenericCondition.createConditionList(idCondition);
final GenericQuery query = new GenericQuery(CatalogModel._TYPECODE, gl);
final GenericSearchQuery gsq = new GenericSearchQuery(query);
gsq.setCount(5);
gsq.setUser(userService.getUserForUID("ahertz"));
gsq.setCatalogVersions(catalogVersionService.getCatalogVersion("clothes", "Online"));
final SearchResult<CatalogModel> searchResult = genericSearchService.search(gsq);
Behind the Scenes
Behind the scenes, the GenericQuery is ultimately converted into a FlexibleSearchQuery by the toFlexibleSearch method and than executed as FlexibleSearch query:
public String toFlexibleSearch(final Map valueMap){
final StringBuilder sb = new StringBuilder();
toFlexibleSearch(sb, null, valueMap);
return sb.toString();
}
GenericSearch in UML
The UML diagram below illustrates the relationship between the main GenericSearch objects.
Related Information
How to Implement a Custom Search Provider
http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/querycriteria.html
Working with Lucene Search
This is custom documentation. For more information, please visit the SAP Help Portal
71
5/27/2022
The SAP Commerce object for creating or managing an index for the lucenesearch extension is a LuceneIndex object.
Access a LuceneIndex
The overall SAP Commerce object to create or manage a certain index for the lucenesearch extension is a LuceneIndex object, represented in the Hybris Management
Console (HMC) by the Lucene index editor. To reach all available LuceneIndex objects, navigate to System > Lucene search indexes:
Within the HMC representation of a LuceneIndex, you can set details of the Lucene index through subeditors, such as the indexed types with their respective attribute
con gurations and the indexed languages.
IndexCon guration
Index con gurations are set and maintained in the Index con guration Editor. This editor also lists the Attribute con gurations set for the indexed type. The following
screenshot shows the editor for such a IndexCon guration object:
This is custom documentation. For more information, please visit the SAP Help Portal
72
5/27/2022
AttributeCon guration
The Attribute con guration Editor can be accessed through the Index con guration Editor and facilitates editing the individual attributes of and indexed type. The following
screenshot shows the editor for such an AttributeCon guration object:
Including a System Language in the Lucene's Index
Language-related settings are speci ed via the LuceneIndex type's Language Con gurations attribute in the form of LanguageCon guration objects. The following
screenshot shows the editor for such a LanguageCon guration object:
This is custom documentation. For more information, please visit the SAP Help Portal
73
5/27/2022
Create a LuceneIndex
This section offers a click path of how to create and manage lucenesearch-related business objects via the Hybris Management Console.
1. Log into the Hybris Management Console.
2. Navigate to System > Lucene search indexes.
3. Right-click on the LuceneSearch indexes entry and click on Create Lucene index.
4. Enter a name for the new Lucene index (myLuceneIndex in the screenshot) and click on the Create button.
5. Right-click on the Index con gurations eld and click on Create Index con guration.
This is custom documentation. For more information, please visit the SAP Help Portal
74
5/27/2022
6. Select a business object type by entering its quali er into the Indexed type eld. The eld has incremental search functionality (also known as "Find as you type") and
will give a list of potential matches. Click on the matching business object type (Product in the screenshot).
7. Click on the Save button.
8. Click on the drop-down menu and select an attribute whose values will be part of the index later on (code in the screenshot).
9. Click on the Create button.
This is custom documentation. For more information, please visit the SAP Help Portal
75
5/27/2022
10. Add any further attributes, if desired.
11. Click on the Save and close button.
12. Back on the LuceneIndex editor page, scroll down and right-click on the Language con gurations eld, then click on Create Index language con guration.
13. Select a language to be indexed from the drop-down menu.
14. Click on the Save and close button.
15. Back on the LuceneIndex editor page, click on the Save button.
16. Click on the Rebuild index button.
This is custom documentation. For more information, please visit the SAP Help Portal
76
5/27/2022
17. A pop-up window will inform you whether the index has been built successfully. Close the pop-up window by clicking on the Close Window button.
18. Back on the LuceneIndex editor page, click on the Test search tab.
19. Enter a search string into the Search pattern eld. The asterisk (*) works as a wildcard.
20. The Hybris Management Console will show you a list of all search results that match the search pattern.
This is custom documentation. For more information, please visit the SAP Help Portal
77
5/27/2022
Related Information
lucenesearch Extension - Technical Guide
hmc Extension
hMC - End User Guide
lucenesearch Extension
The lucenesearch extension provides the open source search engine Apache Lucene to SAP Commerce. It is the default search engine by factory settings. Lucene is a
fast, full text search engine released under the Apache license.
Unlike the SAP Commerce FlexibleSearch, Lucene uses indexes and only nds items that are included in an index. Also, the FlexibleSearch directly returns SAP Commerce
items as stored in the database, while the Lucene optionally allows processing items during indexing via Analyzer classes.
 Note
An SAP Commerce extension may provide functionality that is licensed through different SAP Commerce modules. Make sure to limit your implementation to the
features de ned in your contract license. In case of doubt, please contact your sales representative.
Locating the LuceneSearch Index Files
The location on the le system where LuceneSearch index les are located is de ned by two SAP Commerce properties. The primary property is named
lucenesearch.indexdir. This property points to the directory into which the LuceneSearch indexes will be written. The factory default value for the lucenesearch.indexdir
property is <${HYBRIS_DATA_DIR}>/luceneindex. The Lucene indexes will therefore be written to <${hybris}>/data/luceneindexes.
Please also refer to the SAP Commerce Forum
.
Limiting Search Results
The SAP Commerce implementation of the LuceneSearch runs searches on entire types and attributes. Unlike the FlexibleSearch (see FlexibleSearch), for example, the
LuceneSearch cannot be affected by restrictions (see Restrictions) as it does not use SAP Commerce items, but full text. To allow limiting the results retrieved by the
LuceneSearch, an Index con guration allows running FlexibleSearch statements on the LuceneSearch results.
Please refer to the indexedDataParams entry in the table, the SAP Commerce Forum
and SAP Customer Experience Experts
for details.
Type Overview on the lucenesearch Extension
A Lucene-based search index in the SAP Commerce consists of ve types which are subtypes of the AbstractLuceneItem type:
LuceneIndex
Represents one Lucene index le. It must contain at least one IndexCon guration, can contain a LanguageCon guration and offers methods to execute searches on
the index it represents.
IndexCon guration
An IndexCon gurationAttributeCon gurations. IndexCon guration objects de ne that a SAP Commerce type is going to be part of the Lucene index, and speci es
details for indexing that type (such as the attributes to be indexed, etc).
An IndexCon guration requires at least one is a container for a Collection of AttributeCon guration to be set. An IndexCon guration with no
AttributeCon gurations would not have any attributes to be indexed for the speci ed type, and therefore index no data.
AttributeCon guration
An AttributeCon guration object de nes that an attribute of a SAP Commerce type is going to be part of the Lucene index, and speci es details for indexing that
attribute.
An IndexCon guration requires at least one AttributeCon guration to be set. An IndexCon guration with no AttributeCon gurations would not have any
attributes to be indexed for the speci ed type, and therefore index no data.
LanguageCon guration
A LanguageCon guration object de nes that the index includes a given system language, and speci es details for indexing SAP Commerce items in that system
language.
Specifying no LanguageCon guration will cause the lucenesearch extension not to use the index as the index would not contain any language-related data.
Trying to run a Lucene search in a system language that is not included in the index' LanguageCon guration will cause the lucenesearch extension not to use
the index as the language-related data in the index would not match the current system language. For example, trying to run a Lucene index which has been
built for en only when the system language is set to de will fail.
IndexUpdate An IndexUpdate object links between an IndexCon guration is a container for a Collection of and an item in the SAP Commerce. It represents an item
whose index entry has to be updated at the related IndexCon guration. It will be created automatically at item modi cation and will be processed by the update jobs
(and removed afterwards). So this type is for internal use only.
This is custom documentation. For more information, please visit the SAP Help Portal
78
5/27/2022
LuceneIndex
A LuceneIndex is the container for a Collection of IndexCon guration objects and LanguageCon guration objects.
Attribute name
Attribute type
Mandatory
Description
indexCon gurations
IndexCon gurationCollection
no
Jalo-only attribute. Retrieves all related IndexCon guration 's. Entries are retrieved via a FlexibleSearch stat
SELECT {pk} FROM {IndexConfiguration} WHERE {luceneIndex}
languageCon gurations
LanguageCon gurationCollection
no
= ?luceneIndex
Jalo-only attribute. Retrieves all related LanguageCon guration 's. Entries are retrieved via a FlexibleSearch
SELECT {pk} FROM {LanguageConfiguration} WHERE {luceneIndex}
pendingUpdatesCount
java.lang.Integer
no
= ?luceneIndex
The number of all IndexUpdate objects that are assigned to the IndexCon gurations assigned to the Lucene
SELECT COUNT({up.pk}) FROM {IndexUpdate AS up JOIN IndexConfiguration AS cfg ON {up
postQueryFilterClassName
java.lang.String
no
Name of a class that implements the PostQueryFilter interface for ltering items from the search result
rebuildStartTimestamp
java.util.Date
no
Timestamp of when the last full build of the LuceneIndex (rebuildIndex()) has been started.
rebuildEndTimestamp
java.util.Date
no
Timestamp of when the last full build of the LuceneIndex (rebuildIndex()) has ended.
upToDate
java.lang.Boolean
yes
Jalo-only attribute. Tells wether the index is up-to-date. By default implementation (DefaultIndexedDataFacto
have a modi edtime attribute returning null) or
the modi edtime attribute is later than the rebuildStartTimestamp of the LuceneIndex
SELECT COUNT( {pk} ) FROM {Product AS indexed} WHERE {modifiedtime} IS NULL O
AND ( {indexed.catalog} IN ({{ SELECT {PK} FROM {Catalog} WHERE {id} = 'cloth
IndexCon guration
An IndexCon guration is a container for a Collection of AttributeCon gurations. IndexCon guration objects de ne that a SAP Commerce type is going to be part of the
Lucene index, and speci es details for indexing that type (such as the attributes to be indexed, etc).
An IndexCon guration requires at least one AttributeCon guration to be set. An IndexCon guration with no AttributeCon gurations would not have any attributes to be
indexed for the speci ed type, and therefore index no data.
Attribute name
Attribute type
Mandatory
Description
activationAttribute
AttributeDescriptor
no
Optional descriptor of boolean attribute. Instances must have the value true in this attribute to be ind
allAvailableAttributes
lucene_AttributeDescriptorCollection
yes
Returns all attributes of the type speci ed by the indexedType attribute. Jalo-only attribute.
attributeCon gurations
AttributeCon gurationCollection
no
A Collection of all AttributeCon guration objects assigned to this IndexCon guration. Jalo-only att
availableActivationAttributes
lucene_AttributeDescriptorCollection
yes
Jalo-only attribute. Deprecated
availableGroupingAttributes
lucene_AttributeDescriptorCollection
yes
Jalo-only attribute. Deprecated
availableIndexableAttributes
lucene_AttributeDescriptorCollection
yes
Jalo-only attribute. Gets all available attributes of the speci ed type which are indexable.
groupingAttribute
AttributeDescriptor
no
Optional descriptor of an attribute that puts the indexed item into one or more groups; see the docum
includedTypes
ComposedType
no
Speci es the types included for creating the index. Here you have the possibility to reject speci c su
This is custom documentation. For more information, please visit the SAP Help Portal
79
5/27/2022
Attribute name
Attribute type
Mandatory
Description
indexedDataFactoryClassName
java.lang.String
no
Name of a class that implements IndexedDataFactory (see APIDoc). As Default the DefaultIndexedDa
indexedDataParams
java.lang.String
no
Additional parameters which may be evaluated by the assoziated IndexedDataFactory. Please also re
indexedType
ComposedType
yes
The speci c item type whose instances will be indexed. Initial, no more editable after creation.
luceneIndex
LuceneIndex
yes
The LuceneIndex to which the IndexCon guration is assigned.
pendingUpdates
IndexUpdateCollection
no
A Collection of all IndexUpdate objects containing items of the speci ed item type which where exist
SELECT COUNT({up.pk}) FROM {IndexUpdate AS up JOIN IndexConfiguration AS cfg
AttributeCon guration
An AttributeCon guration object de nes that an attribute of a SAP Commerce type is going to be part of the Lucene index, and speci es details for indexing that attribute.
An IndexCon guration requires at least one AttributeCon guration to be set. An IndexCon guration with no AttributeCon gurations would not have any attributes to be
indexed for the speci ed type, and therefore index no data.
Attribute name
Attribute type
Mandatory
Description
availableIndexableAttributes
lucene_AttributeDescriptorCollection
yes
Direct mapping of the
availableIndexableAttribute attribute of the
IndexCon guration to which the
AttributeCon guration is assigned. Jaloonly attribute.
exact
java.lang.Boolean
yes
Shows that this attribute text must be
indexed exactly without any stemming
mechanism e.g. codes or identi cation
numbers. Defaults to Boolean.FALSE.
eldName
java.lang.String
no
Field name within the lucene index where the
attribute will be stored
indexCon guration
IndexCon guration
yes
The IndexCon guration where this
con guration is related to.
indexedAttribute
AttributeDescriptor
yes
Gets the attribute de nition this
con guration represents. Is limited to the
values of the availableIndexableAttributes
attribute.
storeData
java.lang.Boolean
yes
Tells that the original text has to be stored
inside the lucene index as well. Defaults to
Boolean.TRUE.
weight
java.lang.Double
yes
The weighting of the attribute within the
Lucene index. Must be greater than 0.
Defaults to new Double(1.0).
LanguageCon guration
LanguageCon guration
A LanguageCon guration object de nes that the index includes a given system language, and speci es details for indexing SAP Commerce items in that system language.
Note: For each language an own lucene index le will be created technical.
- Specifying no LanguageCon guration will cause the lucenesearch extension not to use the index as the index would not contain any language-related data.
- Trying to run a Lucene search in a system language that is not included in the index' LanguageCon guration will cause the lucenesearch extension not to use the index as
the language-related data in the index would not match the current system language. For example, trying to run a Lucene index which has been built for en only when the
system language is set to de will fail.
A LanguageCon guration speci es a system language for the index and optionally an Analyzer de nition. For example, the ystorefoundation LuceneIndex uses the following
code snippet for the system language en:
PerFieldAnalyzerWrapper wrapper = new PerFieldAnalyzerWrapper( new org.apache.lucene.analysis.snowball.SnowballAnalyzer("English", Sto
wrapper.addAnalyzer(
ystorefoundationpackage.constants.YStoreFoundationConstants.LuceneIndex.ARTICLE_ID,
new KeywordAnalyzer()
);
wrapper.addAnalyzer(
ystorefoundationpackage.constants.YStoreFoundationConstants.LuceneIndex.ARTICLE_NAME,
new ArticleNameAnalyzer()
);
wrapper.addAnalyzer(
ystorefoundationpackage.constants.YStoreFoundationConstants.LuceneIndex.ARTICLE_KEYWORDS,
This is custom documentation. For more information, please visit the SAP Help Portal
80
5/27/2022
new ArticleNameAnalyzer()
);
return wrapper;
Attribute name
Attribute type
Mandatory
Description
analyzerDe nition
java.lang.String
no
De nes the analyzer class used for normalization of the
documents of this LanguageCon guration. Has to be given in
Java-Syntax returning a org.apache.lucene.analysis.Analyzer
instance f.e. "return new
org.apache.lucene.analysis.snowball.SnowballAnalyzer("German",
GermanAnalyzer.GERMAN_STOP_WORDS );"
indexedLanguage
Language
yes
The system language to use for the index.
luceneIndex
LuceneIndex
yes
The LuceneIndex to which the LanguageCon guration is
assigned.
IndexUpdate
An IndexUpdate object links between an IndexCon guration and an item in the SAP Commerce. It represents an item whose index entry has to be updated at the related
IndexCon guration. It will be created automatically at item modi cation and will be processed by the update jobs (and removed afterwards). So this type is for internal use
only.
Attribute name
Attribute type
Mandatory
Description
item
Item
no
Reference to the represented item. Jalo-only
attribute.
itemPK
PK
no
The PK of the referenced item. Initial.
indexCon guration
IndexCon guration
no
The con guration the related index entry is
managed by. Initial.
updateIndexCronJob
CronJob
no
The cron job responsible for updating the
related index entry. Initial.
remove
java.lang.Boolean
no
The index entry has to be removed, not only
updated. Initial. Defaults to Boolean.FALSE.
inProgress
java.lang.Boolean
yes
The index entry will be updated at the
moment. Defaults to Boolean.FALSE.
LuceneSearch-Related Jobs
For details on Jobs, please refer to The cronjob Service.
RebuildIndexJob
Daily run Job that calls the LucenesearchManager class' rebuildAllIndexes() method. This method iterates over all available LuceneIndex es and calls rebuildIndex() on each
of them.
In essence, this Job completely rebuilds the LuceneIndex es once every day.
UpdateIndexJob
The UpdateIndexJob is a Job run every minute that updates the LuceneIndex instances incrementally. Instead of indexing every single SAP Commerce item, the
UpdateIndexJob only updates items that have been scheduled for re-indexing. Basically, the course of action is like this:
1. the UpdateIndexJob is activated every minute
2. the UpdateIndexJob checks whether any items have been scheduled for re-indexing during the minute
3. any scheduled items are re-indexed
4. the UpdateIndexJob is "sent to sleep" again until the next activation
The Hybris Management Console automatically schedules created or modi ed items for re-indexing. On the SAP Commerce API layer, you will need to do the scheduling
manually.
To schedule a SAP Commerce item for re-indexing, call the UpdateIndexJob.scheduleUpdate( ...) method, as in:
UpdateIndexJob.scheduleUpdate(Collections.singleton(item), false);
To get feedback on whether the item will actually be re-indexed, evaluate the return value of the UpdateIndexJob.scheduleUpdate( ...) method, as in:
This is custom documentation. For more information, please visit the SAP Help Portal
81
5/27/2022
Item item = getItem( e );
if( UpdateIndexJob.scheduleUpdate( Collections.singleton( item ), false ) )
{
System.out.println( "update is scheduled" );
}
else
{
System.out.println( "item is not part of any index" );
}
An index update potentially contains tens of thousands of SAP Mulitichannel Suite items. Therefore, an index update with a very large number of SAP Commerce items to be
re-indexed might cause the UpdateIndexJob to use up a large amount of system memory. As the UpdateIndexJob is a SAP Commerce cron job, it runs within the SAP
Commerce's Virtual Machine. An index update with a large number of SAP Commerce items might cause the Java Virtual Machine to get slow or possibly even run out of
memory. Therefore, the UpdateIndexJob has a limit of how many items to re-index in one single pass. This limit is speci ed in the UpdateIndexJob 's maxUpdatesPerRun
attribute (defaults to 2400).
If the full set of items to be re-indexed exceeds this limit (that is, if there are more than 2400 items to be re-indexed), then the rst batch of 2400 items is indexed with the
rst UpdateIndexJob run, the second batch of 2400 items is indexed with the second UpdateIndexJob run, and so on. As the UpdateIndexJob is run every minute, indexing a
large number of SAP Commerce items might take several minutes altogether. Therefore, we recommend using the rebuildIndex() method if you need a fully completed index
right away and using an incrementally updated index is not an option. However, running a full index rebuild is likely to cause heavy load on the server(s) running the SAP
Mulitichannel Suite and the database.
PostQueryFilter
To affect Lucene search results depending on the user account, a LuceneIndex object can optionally reference a PostQueryFilter class. A PostQueryFilter must implement the
PostQueryFilter interface. To reference a PostQueryFilter, specify the fully quali ed Java classname of the PostQueryFilter to the LuceneIndex type's
postQueryFilterClassName attribute. For example, by default the hmc Lucene index references the de.hybris.platform.lucenesearch.jalo.HMCPostQueryFilter
PostQueryFilter.
Out of the box, the SAP Commerce comes with four implementations of the PostQueryFilter interface:
DefaultPostQueryFilter
1. removes the search results which are instances of types to which the user has no access
2. skips further execution if the disableExecution attribute of the FlexibleSearch is set to true
3. also skips further execution if no Restrictions apply to any of the searched types
4. sorts search results by types
5. removes invalid search results (results that are restricted by search restrictions)
HMCPostQueryFilter (subtype of DefaultPostQueryFilter)
functionality as with the DefaultPostQueryFilter, but limits search results to types to which the current user has access rights in the Hybris Management
Console. No limitations apply to search results of members of the admingroup usergroup.
PassThroughPostQueryFilter
Does not affect the Lucene search results in any way.
TestPostQueryFilter (internal use for unit tests)
Using the LuceneSearch Via the SAP Commerce API
Creating an Index
To create a LuceneIndex, there are two approaches at your disposal:
via the SAP impex extension
via the LucenesearchManager 's createLuceneIndex( ...) method, as in the following code snippet (taken from the CmsManager 's createEssentialData( ...) method):
LucenesearchManager lm = LucenesearchManager.getInstance();
indexCms = lm.createLuceneIndex( CmsConstants.SEARCHINDEX_WEB_CONTENT );
indexCms.createLanguageConfiguration( getSession().getC2LManager().getLanguageByIsoCode( "en" ) );
indexCms.createLanguageConfiguration( getSession().getC2LManager().getLanguageByIsoCode( "de" ) );
indexConf = indexCms.createIndexConfiguration( pageContentType, indexedPageContentAttributes );
indexConf.setGroupingAttribute( pageContentType.getAttributeDescriptor( PageContent.WEBSITE ) );
indexConf = indexCms.createIndexConfiguration( textParagraphType, indexedTextParagraphAttributes );
indexConf.setGroupingAttribute( textParagraphType.getAttributeDescriptor( TextParagraph.WEBSITE ) );
indexConf = indexCms.createIndexConfiguration( navigationElementType, indexedNavigationElementAttributes );
indexConf.setGroupingAttribute( navigationElementType.getAttributeDescriptor( TextParagraph.WEBSITE ) );
Keeping Indexes Up to Date
This is custom documentation. For more information, please visit the SAP Help Portal
82
5/27/2022
The Lucene search engine relies on reverse indexes to look up search results. These reverse indexes are not stored on the SAP Commerce's database, but on the application
server's local le system. By consequence, every node in a SAP Mulitichannel Suite cluster must keep an individual set of indexes. This also means that cron jobs rebuilding
and / or updating a LuceneIndex need to be run individually on every single node in a cluster. As cron job execution is bound to a given node on a cluster, you will need to
create as many instances of Lucene-related cron jobs as there are nodes in the cluster, and assign one individual cron job instance to one individual node.
Out of the box, SAP Commerce creates four cron job instances for each of both the RebuildIndexJob and the UpdateIndexJob to re ect this. Each of the cron job instances is
bound to run on one individual cluster node:
Cron jobs on node 0:
Cluster 0: Lucenesearch-RebuildIndex-Job
Cluster 0: Lucenesearch-UpdateIndex-Job
Cron jobs on node 1:
Cluster 1: Lucenesearch-RebuildIndex-Job
Cluster 1: Lucenesearch-UpdateIndex-Job
Cron jobs on node 2:
Cluster 2: Lucenesearch-RebuildIndex-Job
Cluster 2: Lucenesearch-UpdateIndex-Job
Cron jobs on node 3:
Cluster 3: Lucenesearch-RebuildIndex-Job
Cluster 3: Lucenesearch-UpdateIndex-Job
There are two basic approaches to keeping an index up to date: rebuilding the index and updating the index.
Rebuilding an Index
Rebuilding an index means that the existing index is discarded and re-built from scratch.
To rebuild an index, call the LuceneIndex class' rebuildIndex() method, such as:
LucenesearchManager.getInstance().getLuceneIndex("ystorefoundation").rebuildIndex();
Updating an Index
To update an index for an item, there are two basic approaches:
calling the update manually
To trigger an index update on a SAP Commerce item, call the LucenesearchManager class' updateAllIndexesForItem( Item item) method, passing the item as a
parameter, such as:
LucenesearchManager.getInstance().updateAllIndexesForItem( product865 );
relying on the SAP Commerce's UpdateIndexJob
Please refer to the UpdateIndexJob section for details on scheduling items for re-indexing.
Searching Through an Index
To start a search on a LuceneIndex object, call the searchItems(...) method, such as:
LuceneIndex lui = LucenesearchManager.getInstance().getLuceneIndex("ystorefoundation");
result = lui.searchItems(
ctx,
pattern,
page*perPage,
perPage
);
As the indexes contain actual SAP Commerce data, the same search query is likely to yield different numbers of search results for different system languages.
Related Information
Working with Lucene Search
Commerce Platform Search Mechanisms
Commerce Platform Web Services
The SAP Commerce web service framework is based on RESTful architecture, thereby providing secure CRUD access to all models in the ServiceLayer over a widely adopted
protocol. This further enhances and simpli es the inclusion of SAP Commerce in your software architecture.
This is custom documentation. For more information, please visit the SAP Help Portal
83
5/27/2022
You can nd further information in the sections below:
Web Services
This section introduces business-level overview of web services and the motivations for including them in SAP Commerce.
Key Features and Implementation Details
This section presents various key features and requirements of the SAP Commerce WebService API and explains details of the architecture and implementation.
Web Services in Action
This section holds general information about the usage of different clients for SAP Commerce Web Services API.
Web Services
As software solutions have increased in complexity over the last several years, an emerging requirement has arisen to allow software running on disparate platforms and
developed in various languages to communicate with one another and transfer data in a simple, extensible, and intuitive manner. Web services and in particular RESTful web
services have gained in popularity as they offer an elegant and extensible solution to this problem.
As described in the following sections, we have chosen to base our web service framework on RESTful architecture, and thereby provide secure CRUD access to all models in
the service layer over a well understood and widely adopted protocol. This further enhances and simpli es the inclusion of SAP Commerce in our customers' software
architectures.
Common Features of REST and SOAP Architectures
The rst necessary choice when developing a web services solution is to determine which of the two main frameworks to base the solution upon: REST or SOAP. Both share a
number of common features:
Each web services call follows the standard HTTP stateless client-software request-response protocol.
Each web services call is a self-contained message identifying the server required by web services and any data needed for the service.
Each web services call often triggers a high-level service to run, not simply a low level function call, like Remote Procedure Calls (RPC).
Messages are human-readable as they are sent and received typically in XML or JSON representation over HTTP.
As calls are made over HTTP, any computer that is connected to the internet can offer or access web services.
A user can be completely unaware of the implementation details, for example platform or language on the server side.
Differences Between REST and SOAP Architectures
Although sharing several features, SOAP and REST differ in their focus.
REST
RESTful web services are focused on resources. A resource is some logical entity in the system, such as User, Catalog, Image and so on. All resources are identi ed by a
unique URI. The speci c HTTP method used when calling this URI, that is POST, GET, PUT or DELETE, speci es which of the four CRUD operations to invoke on that resource.
Any necessary supporting data is passed either as attributes appended to the URI or in the body of the message.
SOAP
The SOAP approach in contrast focuses on method calls rather than resources, which though more exible than the earlier solutions to remote collaboration such as
Common Object Request Broker Architecture (CORBA), is more complex and rigid than the RESTful paradigm.
A tabular comparison is given below:
SOAP
REST
Name
Simple Object Access Protocol
REpresentational State Transfer
Complexity
High
Low
Popularity
15% Market
85% Market
Released
1998
2000
Protocol
Focuses on publishing an API usually via a machine-readable
Focuses on mapping server-based resources to unique URIs,
XML le, called the Web Services Description Language
and CRUD operations on those resources to the HTTP
(WSDL).
methods POST, GET, PUT and DELETE.
The client can then call methods of the web services via
XML-based SOAP messages.
Spring support
XFire offers a solution for exposing Spring beans as SOAP-
Spring has very strong high-level annotation support for
based web services.
REST.
Due to its simpler protocol and extensive Spring support, SAP Commerce uses the RESTful model as a basis for web services framework.
This is custom documentation. For more information, please visit the SAP Help Portal
84
5/27/2022
SAP Commerce WebService API
The main purpose of the SAP Commerce WebService API is to facilitate secure CRUD access to models in the service layer. In addition it also addresses a number of other
important related issues discussed in Key Features and Implementation Details and abbreviated here:
Automatically generated code: There is some code required for each Model that is to be accessed via web services. This code is automatically generated, so that any
items added to SAP Commerce are immediately available when SAP Commerce is deployed. This generated logic provides default RESTful access, which can be
overridden if special custom behavior is required.
Security: We require an efficient and intuitive framework for specifying and enforcing security constraints on all RESTful calls made to the SAP Commerce. The SAP
Commerce WebService API provides several ways to specify to which models and attributes of models a caller should have access. Because the web service protocol
is stateless, like other HTTP protocols, authorization and authentication is required at each call.
Commands: The WebService API enables to invoke commands that allow a user for example to place an order or create, start, or abort CronJob. Users may also
create their own commands.
Performance: There are several approaches that enable to improve the performance and are included in the SAP Commerce WebService API:
Caching: As with all potentially expensive calls in the SAP Commerce system, the web services architecture must be structured to allow caching where
possible.
Attribute selection: Some models contain many attributes, which results in signi cant amounts of XML to marshall/unmarshall and transmit. It is therefore
possible for the user to specify which subset of attributes are required in the responses, which in consequence can lead to reduced traffic.
Paginating: We also support efficient paginating when returning large collections of resources in a response.
FlexibleSearch query: Another way to reduce the amount of retrieved data is to use the FlexibleSearch query. It enables to get only the speci ed information
that is interested for the user.
Key Features and Implementation Details
The SAP Commerce WebService API allows external applications to communicate with SAP Commerce using RESTful web service calls. You can use it for performing
authenticated CRUD (Create, Read, Update and Delete) operations on Models in the ServiceLayer, and for invoking commands.
The WebService API simpli es the inclusion of SAP Commerce in other software architectures. It allows them to interact with SAP Commerce with a widely adopted,
extensible, and intuitive protocol.
RESTful web service calls are based on the concept of viewing everything as a resource. Each resource can be accessed individually and it offers a piece of functionality, such
as order management or user management. The SAP Commerce WebService maps SAP Commerce ServiceLayer Models and commands to RESTful resources, and
marshals them into XML or JSON, and the other way round for transmitting them over the Internet.
The SAP Commerce WebService infrastructure is built on the following standards and frameworks:
RESTful web service protocol
JAX-RS (JSR-311) annotation-based RESTful framework
Jersey JAX-RS implementation
Spring web service support
The following discussions assume a basic understanding of these terms.
Architecture of the RESTful-Based SAP Commerce WebService API
The main aim of the SAP Commerce WebService framework is to provide secure, RESTful CRUD operations on items in SAP Commerce without the need for users to write
plumbing code. A secondary purpose is to allow invoking of commands also through RESTful calls. In conformance with the RESTful web services and JAX-RS, items are
exposed via so-called resources, which are units of transfer for RESTful web services. Resources serve as the endpoint, to which clients make RESTful web service calls. Any
information that can be named can be a resource: a document or image, a collection of other resources, a non-virtual object, for example a person. Every type in the SAP
Commerce system gets exposed as a resource and therefore for each type a resource class gets generated.
Because the data to manipulate are SAP Commerce Models in the ServiceLayer, a mechanism for mapping RESTful resources to SAP Commerce Models is used.
This is custom documentation. For more information, please visit the SAP Help Portal
85
5/27/2022
Figure: The basic ow of the WebService framework.
The SAP Commerce Model is a complex object with SAP Commerce speci c logic, and is not amenable to marshalling/unmarshalling to/from XML with JAXB. Therefore SAP
Commerce introduces intermediary simple objects DTOs (Data Transfer Objects), that have a one-to-one mapping to the underlying Models yet are themselves suitable for
such marshaling or unmarshalling. The resource classes use a feature called a GraphTransformer to convert a SAP Commerce Model to and from a DTO. The DTO is then
itself marshaled into XML using JAXB and sent across the wire. See the gure presenting the overview of the conversion process.
For each new Model that you want to expose via RESTful web services, there is considerable plumbing code required including:
DTOs
Resources
Spring context
This default code is automatically generated during the build process for each Model in SAP Commerce. In addition, it is possible for users to easily override the default
implementation with their own code. This is done in such a way that a custom code is not erased when the default code is regenerated.
While the caller (client) may know which resource, collection of resources or command should be accessed on the server, then it should rst be determined to which URI the
request is to be sent. This brings us to the topic URI Mapping.
URI Mapping
Following the JAX-RS and Jersey design, resources are simple POJOs that have been annotated with JAX-RS annotations. These describe to which URI each resource is
mapped. As an example, consider the CatalogsResource:
@Path("/catalogs")
public class CatalogsResource extends AbstractCollectionResource<Collection<CatalogModel>>{
..
@GET
public Response getAllCatalogs(){
return createGetResponse().build(CatalogsDTO.class);
}
..
@Path("{catalog}")
public AbstractYResource getCatalogResource(@PathParam("catalog")final String resourceKey){
This is custom documentation. For more information, please visit the SAP Help Portal
86
5/27/2022
final CatalogResource resource =resourceCtx.getResource(CatalogResource.class);
resource.setResourceId(resourceKey );
resource.setParentResource(this);
return resource;
}
..
}
The example illustrates some important points:
The CatalogsResource is mapped to the URI /catalogs
If the client request an HTTP GET method with the URI http:// root uri /catalogs, the method getAllCatalogs in CatalogsResource is invoked. It returns a
response with a CatalogsDTO, which is converted via JAX-B to XML and returned to the caller.
If a URI is of the form http:// root uri /catalog/ catalogVersion, the method getCatalogResource is invoked instead, with the value of catalogVersion received as
input. This method is then identi ed and forwards the request to the appropriate CatalogResource. That subresource then handles the call in a similar fashion,
possibly returning a CatalogDTO in a response, or perhaps itself calling further sub-resources.
The method of appending to the end of URIs to intuitively and easily identify a resource in a hierarchy of resources is both intuitive and powerful, and has lent to RESTs wide
adoption.
You can type http:// root uri /application.wadl to retrieve a list of the possible URIs and the resource to which they map, that is the Web Application Description
Language (WADL).
Lists of methods and their descriptions for exemplary resources that may be retrieved, updated, or deleted from a server using the SAP Commerce WebService API are
provided in Web Service API - Reference .
There is a possibility to modify and customize the web.xml le used by your extension, for example to change the web context url. Some informative real examples of the
SAP Commerce WebService API in action can be seen in the following locations:
Web Services Examples : Examples of RESTful requests and the responses they generate
Source code of unit tests showing SAP Commerce WebService API in action:
\platform\ext\platformwebservices\web\testsrc\de\hybris\platform\webservices\functional\Case1Test.java
\platform\ext\platformwebservices\web\testsrc\de\hybris\platform\webservices\CatalogsResourceTest.java
For more information, see the RESTful Web Services Developer's Guide presenting mapping between URIs and resources: https://docs.oracle.com/cd/E19776-01/8204867/820-4867.pdf
.
Default Resources and DTOs
It has already been mentioned that resources and DTOs are used to support the CRUD operations on models in the ServiceLayer. In fact, each model requires two
resources, two DTOs and a common Spring con guration le. Fortunately all these les follow strict conventions derived from JAX-RS, JAX-B, and SAP Commerce. As a
consequence their contents can be determined and automatically generated during the SAP Commerce build process.
The automatic generation is illustrated below for a hypothetical new type MyProduct declared in the myextension-items.xml le of a new extension, called
MyExtension. For each step taken, the generated classes and their locations are also presented.
This is custom documentation. For more information, please visit the SAP Help Portal
87
5/27/2022
An example of generated resource in the CatalogsResource code is presented in the Key Features and Implementation Details section above. Its DTO counterparts are
abbreviated below:
@XmlRootElement(name = "catalogs")
public class CatalogsDTO extends AbstractCollectionDTO{
private List catalogsList;
...
@XmlElement(name = "catalog")
public List getCatalogs(){
return catalogsList;
}
...
@GraphNode(target = CatalogModel.class, factory = GenericNodeFactory.class, uidProperties="id")
@XmlRootElement(name = "catalog")
public class CatalogDTO extends ItemDTO
{
...
@XmlElementWrapper(name = "agreements")
@XmlElement(name = "agreement")
public Collection getAgreements(){
return this._agreements;
}
@XmlElementWrapper(name = "baseStores")
@XmlElement(name = "baseStore")
public Collection getBaseStores(){
return this._baseStores;
}
Some keypoints to observe here include:
The JAX-B annotations in both DTOs depicting how to marshall the DTOs to and from XML
The GraphNode annotation instructing SAP Commerce GraphTransformer to which model the CatalogDTO maps. The CatalogsDTO does not itself map directly to
model, but rather represents a collection of model catalogs.
Examples of the Catalogs and Catalog resources in XML representation:
This is custom documentation. For more information, please visit the SAP Help Portal
88
5/27/2022
http://localhost:9001/ws410/rest/catalogs
<catalogs>
<catalog id="Default" uri="http://localhost:9001/ws410/rest/catalogs/Default"/>
<catalog id="hwcatalog" uri="http://localhost:9001/ws410/rest/catalogs/hwcatalog"/>
<catalog id="clothescatalog" uri="http://localhost:9001/ws410/rest/catalogs/clothescatalog"/>
<catalog id="SampleClassification"
uri="http://localhost:9001/ws410/rest/classificationsystems/SampleClassification"/>
<catalog xsi:type="contentCatalogDTO" id="storetemplate_content"
uri="http://localhost:9001/ws410/rest/contentcatalogs/storetemplate_content"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
<catalog xsi:type="contentCatalogDTO" id="mobileshop_content"
uri="http://localhost:9001/ws410/rest/contentcatalogs/mobileshop_content"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
</catalogs>
http://localhost:9001/ws410/rest/catalogs/Default
<catalog id="Default" pk="8796093055576" uri="http://localhost:9001/ws410/rest/catalogs/Default">
<creationtime>2010-05-04T15:19:21.823+02:00</creationtime>
<modifiedtime>2010-05-04T15:19:22.030+02:00</modifiedtime>
<activeCatalogVersion version="Online" uri="http://localhost:9001/ws410/rest/catalogs/Default/Online"/>
<agreements/>
<basestores/>
<cataloglistcomponent/>
<catalogversions>
<catalogversion version="Online" uri="http://localhost:9001/ws410/rest/catalogs/Default/Online"/>
<catalogversion version="Staged" uri="http://localhost:9001/ws410/rest/catalogs/Default/Staged"/>
</catalogversions>
<defaultCatalog>true</defaultCatalog>
<inclAssurance>false</inclAssurance>
<inclDuty>false</inclDuty>
<inclFreight>false</inclFreight>
<inclPacking>false</inclPacking>
<languages>
<language isocode="de" uri="http://localhost:9001/ws410/rest/languages/de"/>
</languages>
<name>default catalog</name>
<previewURLTemplate>/storefoundation/index.jsf</previewURLTemplate>
<restrictions/>
<rootcategories/>
<supplier uid="testfirma" uri="http://localhost:9001/ws410/rest/companies/testfirma"/>
<territories/>
<urlpatterns/>
<version>Online</version>
</catalog>
Finally with the resources and DTOs created, the build process creates or updates a Spring con guration le generated-platformwebservices-web-spring.xml, in
which the DTOs are wired to the SAP Commerce GraphTransformer and the generated resources are declared:
<bean id="genericGraph" class="de.hybris.platform.webservices.objectgraphtransformer.YObjectGraphTransformer"
scope="singleton">
<property name="graphNodes">
<list>
<value type="java.lang.Class">de.hybris.platform.cms2.dto.contents.containers.ABTestCMSComponentContainerDTO</value>
<value type="java.lang.Class">de.hybris.platform.core.dto.util.AbstractCMSItemReleaseViewDTO</value>
<value type="java.lang.Class">de.hybris.platform.comments.dto.AbstractCommentItemDTO</value>
<value type="java.lang.Class">de.hybris.platform.lucenesearch.dto.AbstractLuceneItemDTO</value>
....
</list>
</property>
</bean>
<bean id="aBTestCMSComponentContainersResource"
class="de.hybris.platform.cms2.resource.contents.containers.ABTestCMSComponentContainersResource"
scope="prototype" parent="abstractResource"/>
<bean id="abstractCMSItemReleaseViewsResource"
class="de.hybris.platform.core.resource.util.AbstractCMSItemReleaseViewsResource" scope="prototype"
parent="abstractResource"/>
<bean id="abstractCommentItemsResource"
class="de.hybris.platform.comments.resource.AbstractCommentItemsResource" scope="prototype"
parent="abstractResource"/>
<bean id="abstractLuceneItemsResource"
class="de.hybris.platform.lucenesearch.resource.AbstractLuceneItemsResource" scope="prototype"
parent="abstractResource"/>
...
For further discussion on the generated artifacts, see:
WebService Resource Concept
WebService DTO Concept
Customized Resources and DTOs
By generating default resource and DTO implementations for each type in SAP Commerce, the complete RESTful CRUD access is offered. However, if the default behavior is
not sufficient for a user, it is always possible to override it with a custom implementation.
There may be different reasons for extending the DTO behavior, for example:
If there is special or unusual JAXB marshaling required for a DTO (Model) attribute
This is custom documentation. For more information, please visit the SAP Help Portal
89
5/27/2022
A user wants some virtual DTO attributes that do not map one-to-one to attributes in the model, but perhaps represent an amalgamation of a number of model
attributes.
A user wants to specify particular conversions to take place, for example from a String to Enum eld.
See WebService DTO Concept for a discussion on these topics.
Similarly, there are reasons why the user may wish to extend the default resource implementations:
If custom logic should be performed before or after a model is updated. For example, when a Cart model is updated you want to recalculate the value of its content.
If special handling of the URI path is required, such that the context in which the current resource is identi ed is extracted from the URI path, for example
rest/Catalog/CatalogVersion.
See WebService Resource Concept for a discussion on Resource overriding.
The code is organized such, that custom implementations are placed in a different location to the default generated implementations. Therefore they are not overwritten
when the default implementations are regenerated.
Steps to Create Custom Extension for Web Services:
You can mark one of your own extensions as a webservice extension:
1. Create a new extension using the yempty template.
2. Add the new extension to localextensions.xml le.
3. In the command line go to the platform directory and call: ant.
4. In the command line, go to the new extension directory and call ant webservice_nature -Dextname=customextension.
Running this task gives the selected extension a nature of platformwebservices extension. It results in:
Generation of a new web.xml le. If one already exists, it is renamed to web.xml.old.
Generation of the extension_name -web-spring.xml located in extension_name /resources directory, unless it already exists there.
An additional entry in the Platform's local.properties le, unless it already exists there:
local.properties
#####################################################################################
# Global flag for an extension which will be a webservice extension in pl
#########################################################################
webservice.module={extensionname}
Such customized extensions you are able to provide any custom binaries into WEB-INF\lib folder and use them in override resources and DTOs.
Spring Bean Con guration for Custom Resources/DTOs
The custom resources and DTOs should be de ned in the extension_name -web-spring.xml le located in extension_name /resources directory:
web-spring.xml
<bean id="myResource" class="de.hybris.platform.resource.CustomTypeResource" scope="prototype"
parent="abstractResource"/>
<bean id="myResources" class="de.hybris.platform.resource.CustomTypesResource" scope="prototyp
parent="abstractResource"/>
//virtual resource
<bean id="diagnosticResource" class="de.hybris.platform.aspecttest.resource.DiagnosticResource
scope="prototype" parent="abstractBaseResource"/>
RESTful Commands
In addition to granting access to models via REST, a secondary aim is to allow the invocation of commands via REST. The solution to this is presented in REST Commands
Tutorial.
Security
Security has become the most important focus in web services, because it is necessary to ensure that exposed transactions and processes are secure, reliable, and available
for the service customers. Therefore you need to ensure that:
Web service calls are sufficiently authenticated and authorized
Only permitted CRUD operations are supported for each user:
Users are able to specify access constraints at the resource level and also more nely at the resource attribute level.
Reauthorization and reauthentication are performed for each RESTful call, as the web services protocol is stateless.
This is custom documentation. For more information, please visit the SAP Help Portal
90
5/27/2022
Detailed information about security strategies used in the SAP Commerce WebServices API is provided in: WebService API - Security Architecture.
Performance
For SAP Commerce, it is of high importance to design its solutions such that they are as performant and efficient as possible. Therefore the following features are included in
the SAP Commerce WebService API:
Caching: As with all potentially expensive calls, you need to support caching wherever possible to avoid unnecessary calls to business logic.
For detailed information, see WebService API - Caching Functionality.
Attribute selection: Some resources contain many attributes, which leads to signi cant amounts of XML to marshalll/unmarshall and transmit. SAP Commerce
allows users to specify the subset of attributes required in the responses, which in consequence should possibly lead to reduced traffic.
See Web Service API - Attribute Selector for more information.
Paginating: When collections of resources are requested, large amounts of data may be retrieved. To avoid performance problems, SAP Commerce allows users to
easily specify the subset of a possibly large collection of resources to return by supporting paginating of results.
For details, see Web Service API - Extended Collection.
FlexibleSearch query: Another way to reduce the amount of retrieved data is to use the FlexibleSearch query. It enables you to get only the speci ed information that
is of interest to the user.
Other Objectives
The support of internationalization and localization (i18n) available in SAP Commerce is also extended to web services. For details, see Web Service API - Session
Language.
The automatically generated plumbing code is accompanied with automatically created documentation, making the URI resource and URI command mappings easy
to access.
platformwebservices Extension
The platformwebservices extension provides the SAP Commerce web service framework.
Having a good understanding of web services, REST, JAX-B, and Jersey after reading documents provided in SAP Commerce Platform Web Services, you can go in to the
implementation details showing our solution.
In Key Features and Implementation Details you may nd description of how each of objectives has been implemented.
The SAP Commerce Server exposes resources that may be accessed by different clients. For examples of how the SAP WebService API can be used from a variety of clients,
see Web Services in Action.
 Note
An SAP Commerce extension may provide functionality that is licensed through different SAP Commerce modules. Make sure to limit your implementation to the
features de ned in your contract license. In case of doubt, please contact your sales representative.
Related Information
SAP Commerce Platform Web Services
Web Service API - Attribute Selector
The Attribute Selector API enables you to con gure a set of attributes to be displayed for a given resource in a client response. When a client sends an HTTP GET request to
retrieve information about the resource, the server sends a response containing all attributes of the resource con gured by Attribute Selector.
Basic Concepts
Resource Attributes
A resource can be composed of the following:
Single attributes that may be simple values, like Strings or Integers, or sub-resources.
Collection attributes that represent a collection of elements, either simple attributes or sub-resources.
Sub-Resources
When a resource refers by one of its attributes, like a collection attribute to another resource, the referenced resource is called a sub-resource. The sub-resource is also a
resource, so it may have its own sub-resources.
The example below presents a response for a customer resource:
http://localhost:9001/ws410/rest/customers/abrode
This is custom documentation. For more information, please visit the SAP Help Portal
91
5/27/2022
<customer uri="http://localhost:9001/ws410/rest/customers/abrode" uid="abrode">
<addresses>
<address uri="http://localhost:9001/ws410/rest/addresses/8796093382679"
pk="8796093382679"/>
</addresses>
<usergroups>
<usergroup uid="customergroup"
uri="http://localhost:9001/ws410/rest/usergroups/customergroup"/>
</usergroups>
<name>Arin Brode</name>
<sessionCurrency uri="http://localhost:9001/ws410/rest/currencies/USD">
<isocode>USD</isocode>
</sessionCurrency>
<sessionLanguage uri="http://localhost:9001/ws410/rest/languages/en">
<isocode>en</isocode>
</sessionLanguage>
<customerID>K2006-C0006</customerID>
<previewcatalogversions/>
</customer>
There are different types of attributes in the example:
single attributes:
simple values: name and customerID
sub-resources: sessionCurrency and sessionLanguage
collection attributes of sub-resources: addresses, usergroups
Resource Representation Types
Resources can be presented in different manners:
Detail representation refers to attributes that are retrieved in a response to a direct request for an unique resource, for example customer resource from example
above.
Reference representation refers to all attributes of sub-resources that are presented in a response, that is: address, usergroup, sessionCurrency and
sessionLanguage.
Resource Selectors
There are two methods of specifying a resource for the Attribute Selector API:
Using Resource Type Name
Resource type name is the the name of root XML element in a detail representation of a resource, like customer. It is also the name of the XML element used in reference
representation of a resource, when a root resource is requested, for example customers.
Resource name is the same as the type name de ned in items.xml le, except for resources that are not generated from types.
Using Sub-Resource Attribute Name
It is common, that the name of the attribute referring to a sub-resource is not the same as the type name of the sub-resource. In the example above, sessionCurrency and
sessionLanguage attributes correspond to currency and language type names.
It would be confusing and non-intuitive to provide always a resource type name. The Attribute Selector API enables to con gure sub-resources by specifying either the
resource name, or the name of the attribute which refers to that sub-resource. Thus, for above example, it is allowed to use sessionCurrency and sessionLanguage names
when referring to sub-resources of the customer resource.
 Note
Precedence of Sub-Resource Attribute Name
If a con guration data for a resource contains two selectors, one using sub-resource attribute name and other using resource type name, the sub-resource attribute
name selector takes precedence.
Levels of Resource Representation
First Level
For a request to a resource, all of the resource attributes are said to be on level 1.
For a request to a collection of resources, that is root resource, attributes of each resource in the collection are also considered to be on level 1.
This is custom documentation. For more information, please visit the SAP Help Portal
92
5/27/2022
Second Level
Considering the rst level attributes of a resource :
If the attribute represents another resource, this sub-resource's attributes are considered to be on level 2.
If the attribute represents a collection that contains another resources, attributes of each resource in the collection are considered to be on level 2.
Attributes are presented only for the rst two levels of resource representation. The restriction has an implication, that for an attribute on the second level, which is not a
simple value but a sub-resource or collection of sub-resources, the attribute is not shown, even if it is not-null. It is because exposing this attribute requires to expose some
of its attributes, at least the uri attribute, which are on the third level. Because attributes from the third level are not presented, it is not possible to present sub-resource
for the second level at all.
Resource Con guration Inheritance
Resources create hierarchy of inheritance, re ecting the one in SAP Commerce models. For example user resource type has two sub-types: customer and employee, but
there may be some more. Thus, customer is considered to be of customer and user type at the same time. Most resources are also of item type, which is a common type for
all model-derived resources.
Type inheritance is included in the Attribute Selector API. If no con guration for a resource type exist, the mechanism tries to nd a con guration for its direct super-type,
then for a super-type's super-type, and so on, upwards in the inheritance hierarchy. In this way the best match is found. It means that all subtypes of a common type can be
con gured in one step by con guring their super-type. It is possible for attributes that exist also in common type.
For example, if a request for a customer resource is done and customer type is not con gured, the con guration for user resource is applied, if exists.
In case of collection of resources, a common super-type is often used to present the collection elements. However every sub-resource in the collection has a type that is a
subtype of the common super-type.
The example below presents a response for a users resource:
http://localhost:9001/ws410/rest/users
<users uri="http://localhost:9001/ws410/rest/users">
<user uri="http://localhost:9001/ws410/rest/employees/admin" uid="admin"/>
<user uri="http://localhost:9001/ws410/rest/customers/anonymous" uid="anonymous"/>
<user uri="http://localhost:9001/ws410/rest/customers/vjdbcReportsUser" uid="vjdbcReportsUser"/>
<user uri="http://localhost:9001/ws410/rest/employees/wf-admin" uid="wf-admin"/>
<user uri="http://localhost:9001/ws410/rest/customers/ppetersonson" uid="ppetersonson"/>
<user uri="http://localhost:9001/ws410/rest/customers/demo" uid="demo"/>
<user uri="http://localhost:9001/ws410/rest/customers/hweaving" uid="hweaving"/>
<user uri="http://localhost:9001/ws410/rest/customers/sbrueck" uid="sbrueck"/>
<user uri="http://localhost:9001/ws410/rest/customers/hpneumann" uid="hpneumann"/>
<user uri="http://localhost:9001/ws410/rest/customers/ahertz" uid="ahertz"/>
<user uri="http://localhost:9001/ws410/rest/customers/abrode" uid="abrode"/>
<user uri="http://localhost:9001/ws410/rest/customers/hschweiger" uid="hschweiger"/>
<user uri="http://localhost:9001/ws410/rest/customers/dkaufmann" uid="dkaufmann"/>
<user uri="http://localhost:9001/ws410/rest/customers/kvitali" uid="kvitali"/>
<user uri="http://localhost:9001/ws410/rest/customers/bpoweronoff" uid="bpoweronoff"/>
<user uri="http://localhost:9001/ws410/rest/customers/tbullet" uid="tbullet"/>
<user uri="http://localhost:9001/ws410/rest/customers/hjaehnig" uid="hjaehnig"/>
<user uri="http://localhost:9001/ws410/rest/customers/mdigit" uid="mdigit"/>
<user uri="http://localhost:9001/ws410/rest/customers/ovh" uid="ovh"/>
<user uri="http://localhost:9001/ws410/rest/customers/nvp" uid="nvp"/>
<user uri="http://localhost:9001/ws410/rest/customers/ariel" uid="ariel"/>
<user uri="http://localhost:9001/ws410/rest/employees/productmanager_wf1"
uid="productmanager_wf1"/>
<user uri="http://localhost:9001/ws410/rest/employees/productmanager_wf2"
uid="productmanager_wf2"/>
<user uri="http://localhost:9001/ws410/rest/employees/productmanager_wf3"
uid="productmanager_wf3"/>
</users>
Every collection element in the above example is of customer or employee type, which are both subtypes of user type. However, all elements are presented as a collection of
user elements and can be con gured uniformly by providing con guration for user type. If a con guration for employee type isl also provided, only employee elements will be
affected. Elements of customer type inherit the con guration from user type.
Attribute Selector API Usage
The Attribute Selector API enables to con gure the set of attributes for a resource that are retrieved as a result of a client request. The API requires an information about a
resource which is the subject of attribute selection and a list of attributes for the resource.
The following approaches for con guration of resources are available:
 Note
Special Cases of Attributes
The uri attribute is treated as special one and is always presented, regardless on the con guration in Attribute Selector API. On the other hand, attributes with empty
values are not retrieved, even if requested in the API con guration.
This is custom documentation. For more information, please visit the SAP Help Portal
93
5/27/2022
Factory Defaults
Factory Defaults is a hard-coded, generic default con guration. A detail representation of a resource includes by default all attributes of the resource. A reference
representation contains only the uri and the unique identi er of the given resource, which is prede ned and cannot be changed. Factory Defaults for a resource are used
when neither static nor dynamic con guration is provided for the resource.
In the example presented above for customer resource, Factory Defaults are used for all attributes. Detail representation is used for customer type, reference
representation is used for sub-resources of customer. For example, the sessionLanguage attribute contains information that are con gured for language resource.
Static Con guration
Static con guration is a basic functionality that allows to de ne which attributes should be retrieved by modifying a con guration in the local project.properties le for
platformwebservices extension. The static con guration is read only on Commerce Platform start, so any changes in the con guration require restarting the Commerce
Platform.
 Note
JUnit Tests
JUnit tests are prepared for the Factory Defaults. If the response of a resource is changed due to the static con guration in Attribute Selector API, tests may end with a
failure.
The syntax for the static con guration entries is as follows:
ws. type .detail = attribute quali er 1, attribute quali er 2, attribute quali er n
ws. type .reference = attribute quali er 1, attribute quali er 2, attribute quali er n
Where:
type is a resource selector given either as the resource type name or a sub-resource attribute name. For details see Resource Selectors.
attribute quali er is a case-insensitive attribute name.
detail form is used to con gure a detail representation of a resource.
reference form is used to con gure a reference representation of a resource.
 Note
Spelling Restrictions
A resource selector name in the static con guration must be written in lowercase.
Dynamic Con guration
Dynamic con guration is an advanced functionality that allows to con gure a set of attributes by specifying them as query parameters in the request URI.
The syntax for the dynamic con guration entry query parameter is as follows:
type _attributes= attribute quali er 1, attribute quali er 2, attribute quali er n
type _attributes_detail= attribute quali er 1, attribute quali er 2, attribute quali er n
type _attributes_reference= attribute quali er 1, attribute quali er 2, attribute quali er n
Where:
type is a resource selector given either as the resource type name or a sub-resource attribute name. For details see Resource Selectors.
attribute quali er is a case-insensitive attribute name.
_detail form is used to con gure a detail representation of a resource.
_reference form is used to con gure a reference representation of a resource.
The following form: type _attributes= attribute quali er 1 is a convenient shortcut to refer to both detail and reference representations. If it is used, it takes precedence over
any other _detail or _reference form used for the resource.
The dynamic con guration takes precedence over the static con guration.
 Tip
No Spelling Restrictions
A resource selector name in the dynamic con guration is case-insensitive and may contain lower- and uppercase letters.
This is custom documentation. For more information, please visit the SAP Help Portal
94
5/27/2022
 Tip
Incorrect use of attribute, for example when con guring an attribute that does not exist, causes an error in Commerce Platform logs. The invalid attribute is skipped, but
other attributes are processed as usually.
Examples of Con guration
Static Con guration Examples
Root Resource
The following con guration in project.properties le:
ws.user.reference=name,sessioncurrency
results in presenting name and sessioncurrency for a user sub-resource of the users root resource. Some collection elements do not expose sessionCurrency attribute,
because it is empty.
 Note
For a brevity, only those parts of responses are presented, that are important for understanding of examples.
http://localhost:9001/ws410/rest/users
<users uri="http://localhost:9001/ws410/rest/users">
<user uri="http://localhost:9001/ws410/rest/employees/admin">
<name>Administrator</name>
</user>
<user uri="http://localhost:9001/ws410/rest/customers/anonymous">
<name>Anonymous</name>
<sessionCurrency uri="http://localhost:9001/ws410/rest/currencies/USD">
<isocode>USD</isocode>
</sessionCurrency>
</user>
<user uri="http://localhost:9001/ws410/rest/customers/ppetersonson">
<name>Peter Petersonson</name>
<sessionCurrency uri="http://localhost:9001/ws410/rest/currencies/USD">
<isocode>USD</isocode>
</sessionCurrency>
</user>
<user uri="http://localhost:9001/ws410/rest/customers/abrode">
<name>Arin Brode</name>
<sessionCurrency uri="http://localhost:9001/ws410/rest/currencies/USD">
<isocode>USD</isocode>
</sessionCurrency>
</user>
<user uri="http://localhost:9001/ws410/rest/employees/productmanager_wf1">
<name>Workflow Product Manager Demouser 1</name>
</user>
<user uri="http://localhost:9001/ws410/rest/employees/productmanager_wf2">
<name>Workflow Product Manager Demouser 2</name>
</user>
<user uri="http://localhost:9001/ws410/rest/employees/productmanager_wf3">
<name>Workflow Product Manager Demouser 3</name>
</user>
</users>
Root Resource with Type Hierarchy
The following con guration in project.properties le:
ws.user.reference=name,sessionlanguage
ws.customer.reference=uid,sessioncurrency
causes that customer type has its own con guration, while employee inherits from user type con guration.
http://localhost:9001/ws410/rest/users
<users>
<user uri="http://localhost:9001/ws410/rest/employees/admin">
<name>Administrator</name>
</user>
<user uri="http://localhost:9001/ws410/rest/customers/anonymous" uid="anonymous">
<sessionCurrency uri="http://localhost:9001/ws410/rest/currencies/USD">
<isocode>USD</isocode>
</sessionCurrency>
</user>
<user uri="http://localhost:9001/ws410/rest/customers/ppetersonson" uid="ppetersonson">
<sessionCurrency uri="http://localhost:9001/ws410/rest/currencies/USD">
<isocode>USD</isocode>
This is custom documentation. For more information, please visit the SAP Help Portal
95
5/27/2022
</sessionCurrency>
</user>
<user uri="http://localhost:9001/ws410/rest/customers/abrode" uid="abrode">
<sessionCurrency uri="http://localhost:9001/ws410/rest/currencies/USD">
<isocode>USD</isocode>
</sessionCurrency>
</user>
<user uri="http://localhost:9001/ws410/rest/employees/productmanager_wf1">
<name>Workflow Product Manager Demouser 1</name>
<sessionLanguage uri="http://localhost:9001/ws410/rest/languages/en">
<isocode>en</isocode>
</sessionLanguage>
</user>
<user uri="http://localhost:9001/ws410/rest/employees/productmanager_wf2">
<name>Workflow Product Manager Demouser 2</name>
<sessionLanguage uri="http://localhost:9001/ws410/rest/languages/de">
<isocode>de</isocode>
</sessionLanguage>
</user>
<user uri="http://localhost:9001/ws410/rest/employees/productmanager_wf3">
<name>Workflow Product Manager Demouser 3</name>
<sessionLanguage uri="http://localhost:9001/ws410/rest/languages/en">
<isocode>en</isocode>
</sessionLanguage>
</user>
</users>
Resource
The following con guration in project.properties le:
ws.user.detail=uid,sessionlanguage
causes that the static con guration overwrites Factory Defaults for customer resource.
http://localhost:9001/ws410/rest/customers/abrode
<customer uri="http://localhost:9001/ws410/rest/customers/abrode" uid="abrode">
<sessionLanguage uri="http://localhost:9001/ws410/rest/languages/en">
<isocode>en</isocode>
</sessionLanguage>
</customer>
Resource with Type Hierarchy
The following con guration in project.properties le:
ws.user.detail=uid,sessionlanguage
ws.customer.detail=name,sessioncurrency
causes that the more speci c type selector for customer takes precedence over less speci c type selector, that is user. Factory Defaults is used for sessionCurrency.
http://localhost:9001/ws410/rest/customers/abrode
<customer uri="http://localhost:9001/ws410/rest/customers/abrode">
<name>Arin Brode</name>
<sessionCurrency uri="http://localhost:9001/ws410/rest/currencies/USD">
<isocode>USD</isocode>
</sessionCurrency>
</customer>
Resource with Sub-Resource Type Name Selector
The following con guration in project.properties le:
ws.customer.detail=name,sessioncurrency
ws.currency.reference=active,isocode
causes that Factory Defaults for sessionCurrency attribute is overwritten by con guration for currency type.
http://localhost:9001/ws410/rest/customers/abrode
<customer uri="http://localhost:9001/ws410/rest/customers/abrode">
<name>Arin Brode</name>
<sessionCurrency uri="http://localhost:9001/ws410/rest/currencies/USD">
<active>true</active>
<isocode>USD</isocode>
</sessionCurrency>
</customer>
This is custom documentation. For more information, please visit the SAP Help Portal
96
5/27/2022
Resource with Sub-Resource Attribute Name Selector
The following entries in project.properties le:
ws.customer.detail=name,sessioncurrency
ws.currency.reference=active,isocode
ws.sessioncurrency.reference=name,symbol
causes that there are two con gurations for sessionCurrency attribute, that is ws.currency.reference and ws.sessioncurrency.reference. In this case
ws.sessioncurrency.reference is chosen, because it is more speci c.
http://localhost:9001/ws410/rest/customers/abrode
<customer uri="http://localhost:9001/ws410/rest/customers/abrode">
<name>Arin Brode</name>
<sessionCurrency uri="http://localhost:9001/ws410/rest/currencies/USD">
<name>US Dollar</name>
<symbol>$</symbol>
</sessionCurrency>
</customer>
Dynamic Con guration Examples
Root Resource
The following con guration in project.properties le:
ws.user.reference=name,sessioncurrency
causes that entries from static con guration are overwritten by dynamic con guration for user type.
Two different URIs:
http://localhost:9001/ws410/rest/users?user_attributes=uid,sessionLanguage
http://localhost:9001/ws410/rest/users?user_attributes_reference=uid,sessionLanguage
retrieve the same results.
http://localhost:9001/ws410/rest/users?user_attributes_reference=uid,sessionLanguage
<users>
<user uri="http://localhost:9001/ws410/rest/employees/admin" uid="admin"/>
<user uri="http://localhost:9001/ws410/rest/customers/anonymous" uid="anonymous">
<sessionLanguage uri="http://localhost:9001/ws410/rest/languages/en">
<isocode>en</isocode>
</sessionLanguage>
</user>
<user uri="http://localhost:9001/ws410/rest/customers/ppetersonson" uid="ppetersonson">
<sessionLanguage uri="http://localhost:9001/ws410/rest/languages/en">
<isocode>en</isocode>
</sessionLanguage>
</user>
<user uri="http://localhost:9001/ws410/rest/customers/abrode" uid="abrode">
<sessionLanguage uri="http://localhost:9001/ws410/rest/languages/en">
<isocode>en</isocode>
</sessionLanguage>
</user>
<user uri="http://localhost:9001/ws410/rest/employees/productmanager_wf1" uid="productmanager_wf1">
<sessionLanguage uri="http://localhost:9001/ws410/rest/languages/en">
<isocode>en</isocode>
</sessionLanguage>
</user>
<user uri="http://localhost:9001/ws410/rest/employees/productmanager_wf2" uid="productmanager_wf2">
<sessionLanguage uri="http://localhost:9001/ws410/rest/languages/de">
<isocode>de</isocode>
</sessionLanguage>
</user>
<user uri="http://localhost:9001/ws410/rest/employees/productmanager_wf3" uid="productmanager_wf3">
<sessionLanguage uri="http://localhost:9001/ws410/rest/languages/en">
<isocode>en</isocode>
</sessionLanguage>
</user>
</users>
Root Resource with Type Hierarchy
The following con guration in project.properties le:
ws.user.reference=name,sessionlanguage
ws.customer.reference=uid,sessioncurrency
This is custom documentation. For more information, please visit the SAP Help Portal
97
5/27/2022
causes that customer has its own con guration, while employee inherits from user type con guration. Moreover, the dynamic con guration overwrites the static one.
http://localhost:9001/ws410/rest/users?user_attributes=uid&customer_attributes=name
<users>
<user uri="http://localhost:9001/ws410/rest/employees/admin" uid="admin"/>
<user uri="http://localhost:9001/ws410/rest/customers/anonymous">
<name>Anonymous</name>
</user>
<user uri="http://localhost:9001/ws410/rest/customers/ppetersonson">
<name>Peter Petersonson</name>
</user>
<user uri="http://localhost:9001/ws410/rest/customers/abrode">
<name>Arin Brode</name>
</user>
<user uri="http://localhost:9001/ws410/rest/employees/productmanager_wf1" uid="productmanager_wf1"/>
<user uri="http://localhost:9001/ws410/rest/employees/productmanager_wf2" uid="productmanager_wf2"/>
<user uri="http://localhost:9001/ws410/rest/employees/productmanager_wf3" uid="productmanager_wf3"/>
</users>
Root Resource with Type Hierarchy
In the example both static and dynamic con guration are applied.
The following con guration in project.properties le:
ws.user.reference=name,sessionlanguage
ws.customer.reference=uid,sessioncurrency
causes that the static con guration for customer type is used. The static con guration for user is overwritten by the dynamic con guration for employee. All users in this
example that are not of customer type are of employee type.
Compare this result with Root Resource with Type Hierarchy.
http://localhost:9001/ws410/rest/users?employee_attributes=uid
<users>
<user uri="http://localhost:9001/ws410/rest/employees/admin" uid="admin"/>
<user uri="http://localhost:9001/ws410/rest/customers/anonymous" uid="anonymous">
<sessionCurrency uri="http://localhost:9001/ws410/rest/currencies/USD">
<isocode>USD</isocode>
</sessionCurrency>
</user>
<user uri="http://localhost:9001/ws410/rest/customers/ppetersonson" uid="ppetersonson">
<sessionCurrency uri="http://localhost:9001/ws410/rest/currencies/USD">
<isocode>USD</isocode>
</sessionCurrency>
</user>
<user uri="http://localhost:9001/ws410/rest/customers/abrode" uid="abrode">
<sessionCurrency uri="http://localhost:9001/ws410/rest/currencies/USD">
<isocode>USD</isocode>
</sessionCurrency>
</user>
<user uri="http://localhost:9001/ws410/rest/employees/productmanager_wf1" uid="productmanager_wf1"/>
<user uri="http://localhost:9001/ws410/rest/employees/productmanager_wf2" uid="productmanager_wf2"/>
<user uri="http://localhost:9001/ws410/rest/employees/productmanager_wf3" uid="productmanager_wf3"/>
</users>
Resource Selectors
No con guration in the project.properties le causes that a form of sessionLanguage and sessionCurrency sub-resources is modi ed by use of Resource Type Name
selectors.
http://localhost:9001/ws410/rest/customers/abrode?language_attributes=active&currency_attributes=isocode,name
<customer uri="http://localhost:9001/ws410/rest/customers/abrode" uid="abrode">
<addresses>
<address uri="http://localhost:9001/ws410/rest/addresses/8796093382679" pk="8796093382679"/>
</addresses>
<usergroups>
<usergroup uid="customergroup" uri="http://localhost:9001/ws410/rest/usergroups/customergroup"/>
</usergroups>
<name>Arin Brode</name>
<sessionCurrency uri="http://localhost:9001/ws410/rest/currencies/USD">
<isocode>USD</isocode>
<name>US Dollar</name>
</sessionCurrency>
<sessionLanguage uri="http://localhost:9001/ws410/rest/languages/en">
<active>true</active>
</sessionLanguage>
<customerID>K2006-C0006</customerID>
<previewcatalogversions/>
</customer>
This is custom documentation. For more information, please visit the SAP Help Portal
98
5/27/2022
The same example, but with Sub-Resource Attribute Name selector for sessionCurrency presents, that a usage of more speci c Sub-Resource Attribute Name selector
overwrites the more general Resource Type Name selector.
http://localhost:9001/ws410/rest/customers/abrode?
language_attributes=active&currency_attributes=isocode,name&sessionCurrency_attributes=symbol,conversion
<customer uri="http://localhost:9001/ws410/rest/customers/abrode" uid="abrode">
<addresses>
<address uri="http://localhost:9001/ws410/rest/addresses/8796093382679" pk="8796093382679"/>
</addresses>
<usergroups>
<usergroup uid="customergroup" uri="http://localhost:9001/ws410/rest/usergroups/customergroup"/>
</usergroups>
<name>Arin Brode</name>
<sessionCurrency uri="http://localhost:9001/ws410/rest/currencies/USD">
<conversion>1.38</conversion>
<symbol>$</symbol>
</sessionCurrency>
<sessionLanguage uri="http://localhost:9001/ws410/rest/languages/en">
<active>true</active>
</sessionLanguage>
<customerID>K2006-C0006</customerID>
<previewcatalogversions/>
</customer>
WebService API - Caching Functionality
The SAP Commerce WebService framework supports caching of responses to reduce the amount of information transmitted over the network. This reduces the bandwidth
and processing requirements of the SAP Commerce server. It also helps to improve the responsiveness of web services clients.
The caching functionality allows to use different caching strategies for different resources. Caching is performed by using cache related processors con gured by the
WebService API - Request Processor Chain.
Description of Caching Mechanism
Caching in the SAP Commerce WebService API is realized by ETag, that is a HTTP response header. When the SAP Commerce Server receives a request for some resource, it
generates a unique ETag from current resource state. Then ETag is sent in response header to the client together with requested resource. When the client requests the
same resource for the next time, ETag is automatically included into the request. On the server side the new ETag value is calculated for the requested resource and
compared with the ETag received from the client.
When ETags are the same, the SAP Commerce Server sends a not modi ed code 304 to the client. Server does not have to generate the requested resource again. The
following message is written in the debug log:
The WS call for item <resource_name> was received with etag <ETag_value> therefore caching was used,
and the etag returned is <ETag_value>.
When ETags differ, it means that resource has changed since the last request and the modi ed resource together with a new ETag is sent to the client. The following
message is written in the debug log:
The WS call for item <resource_name> was received with etag <ETag_value> therefore caching was not used,
and the etag returned is <ETag_value>.
Caching Enabling in Web Services
This is custom documentation. For more information, please visit the SAP Help Portal
99
5/27/2022
The default caching strategy may be enabled or disabled for all resources, as it is de ned for abstractResource. This strategy does not reduce the server load, it only saves
bandwidth between the client and the server.
To enable caching in the SAP Commerce WebService API, the following two de nitions should be added to the platformwebservices-web-spring.xml le:
platformwebservices-web-spring.xml
<!-Caching strategies
Gets injected into Resources.
-->
<bean id="cachingStrategy" class="de.hybris.platform.webservices.cache.impl.DefaultCachingStrategy"/>
<!-REST Resources
-->
<bean id="abstractResource" class="de.hybris.platform.webservices.AbstractResource" abstract="true"
scope="prototype">
<property name="rolesResourcesService" ref="rolesResourcesAssignmentService"/>
<property name="serviceLocator" ref="serviceLocator"/>
<property name="cachingStrategy" ref="cachingStrategy"/>
<property name="objectGraph" ref="genericGraph"/>
</bean>
Caching Disabling in Web Services
To disable caching in the SAP Commerce WebService API, the cachingStrategy property should be removed from the abstractResource bean in the platformwebservicesweb-spring.xml le:
platformwebservices-web-spring.xml
<!-Caching strategies
Gets injected into Resources.
-->
<bean id="cachingStrategy" class="de.hybris.platform.webservices.cache.impl.DefaultCachingStrategy"/>
<!-REST Resources
-->
<bean id="abstractResource" class="de.hybris.platform.webservices.AbstractResource" abstract="true"
scope="prototype">
<property name="rolesResourcesService" ref="rolesResourcesAssignmentService"/>
<property name="serviceLocator" ref="serviceLocator"/>
<property name="objectGraph" ref="genericGraph"/>
</bean>
Creating Custom Caching Strategy
It is possible to create custom caching strategies optimized for project requirements. It enables caching for a particular resource and allows to save resources on the server
side.
The following steps should be accomplished to create a custom caching strategy:
Extending AbstractCachingStrategy Class
A custom caching strategy class has to extend AbstractCachingStrategy class, which implements de.hybris.platform.webservices.CachingStrategy interface:
CustomCachingStrategy.java
public class CustomCachingStrategy<RESOURCE> extends AbstractCachingStrategy<RESOURCE>
{
@Override
public String getUID(final AbstractResource resource, final RESOURCE resourceValue)
{
final String uniqueIdentifier;
// compute uniqueIdentifier string based on important resource values
return uniqueIdentifier;
}
}
Registering the Caching Strategy
A custom caching strategy may concern all resources or only a speci c resource.
De ning the caching strategy as a bean:
platformwebservices-web-spring.xml
This is custom documentation. For more information, please visit the SAP Help Portal
100
5/27/2022
<bean id="customCachingStrategy" class="de.hybris.platform.webservices.cache.impl.CustomCachingStrategy"/>
Injection of the customCachingStrategy bean to the resources that should use the caching strategy:
platformwebservices-web-spring.xml
<bean id="addressResource" class="de.hybris.platform.core.resource.user.addressResource" abstract="true"
scope="prototype">
<property name="rolesResourcesService" ref="rolesResourcesAssignmentService"/>
<property name="serviceLocator" ref="serviceLocator"/>
<property name="cachingStrategy" ref="customCachingStrategy"/>
<property name="objectGraph" ref="genericGraph"/>
</bean>
Caching in Request Processor Chain
When processing a request for web services resource, the logic of WebService API - Request Processor Chain is performed. By default, there are two caching-related
processors in the Commerce Platform that may be used for GET request. They can improve the performance by reducing:
CPU utilization for processing the request
Instead of full request processing, some special marker is calculated to limit the CPU usage.
Network bandwidth needed to transport the response
Instead of transmitting the full response, only an empty response is returned with the Not Modi ed (304) status, which should be properly handled on the client side.
Both of those caching processors have very similar processing diagram.
There is a phase of caching marker generation, which then is compared with the one passed within the request header. In they match, the request is treated as cached. In
this case no further processing is needed and the Not Modi ed (304) status is sent as a response to a client. If markers do not match, normal processing is passed to a next
processor. The ow is presented in the diagram:
Caching-Related Processors
The following processors support caching in the SAP Commerce WebService:
LastModi cationCacheRequestProcessor
ETagCacheRequestProcessor
LastModi cationCacheRequestProcessor
It should be used as the rst one in the request processor chain, prior to ETagCacheRequestProcessor. It uses simpler, less CPU consuming algorithm. For a single resource,
the processor returns the last modi cation date, for a collection of resources, it nds the last modi ed ItemModel in the collection. The last modi cation date is then
compared with If-Modifed-Since header value from a request:
com.sun.jersey.spi.container.ContainerRequest.evaluatePreconditions(Date lastModified);
It the requested data was not changed, the server sends a not modi ed code 304 to the client and no CPU consuming calculations are performed. It spares CPU cycles and
bandwidth. As a result it has less performance impact. In case of single resource the complexity is constant for a resource. In case of collection of resources, it depends on
the collection size.
This is custom documentation. For more information, please visit the SAP Help Portal
101
5/27/2022
ETagCacheRequestProcessor
The SAP Commerce WebService framework supports caching of responses to reduce the amount of information to be transmitted over the network. It reduces a bandwidth
and processing requirements of the SAP Commerce Server. It also helps to improve a responsiveness for web services clients. The caching functionality allows to use
different caching strategies for different resources.
Caching is performed by using cache related processors con gured by WebService API - Request Processor Chain.
Web Service API - Context Aware Resources
Context-aware resources enable GET, UPDATE and CREATE operations on each type of resource without ambiguity. They allow SAP Commerce web services to be fully useful
in terms of accessibility of generated resources. An additional advantage is that custom resources are reduced to minimum.
Overview
The type system provides a set of Models, where some are dependent on others. Such Models may have several unique non-primitive attributes, that are other Models. This
means that instances of the same type can have the same primitive unique attributes, but different unique non-primitive attributes. SAP Commerce WebServices contains
resource and DTO classes that correspond to each Model in the system.
The following example presents the solution that eliminates the problem of failure when trying to reach a speci ed resource. Two instances of Car have the same unique
primitive attribute:
<carId>c1</carId>
and different unique non-primitive attribute, which represents manufacturer Model, with unique primitive attribute:
<manufacturerId>m1</manufacturerId>
<manufacturerId>m2</manufacturerId>
Without Context Aware Resources, it is not possible to get any of the cars and the AmbiguousIdenti erException is thrown. The retrieved result is as follows:
http://localhost:9001/ws410/rest/cars/c1
<cars uri="http://localhost:9001/ws410/rest/cars" xmlns:ns2="http://research.sun.com/wadl/2006/10">
<car carId="c1" pk="8796127330403" uri="http://localhost:9001/ws410/rest/cars/c1"/>
<car carId="c1" pk="8796134654301" uri="http://localhost:9001/ws410/rest/cars/c1"/>
</cars>
With Context Aware Resources, both listed cars are accessible:
http://localhost:9001/ws410/rest/cars/c1
<cars uri="http://localhost:9001/ws410/rest/cars" xmlns:ns2="http://research.sun.com/wadl/2006/10">
<car carId="c1" pk="8796127330403" uri="http://localhost:9001/ws410/rest/manufacturers/m1/cars/c1"/>
<car carId="c1" pk="8796134654301" uri="http://localhost:9001/ws410/rest/manufacturers/m2/cars/c1"/>
</cars>
URL Generation
Each instance of a resource in SAP Commerce web services has a unique URL generated that allows to access the resource without ambiguity problems. During the URL
generation all required unique attributes are included in the URL.
This is custom documentation. For more information, please visit the SAP Help Portal
102
5/27/2022
The example below presents a generated URL for an instance of Car Model with a unique primitive attribute:
<carId>c1</carId>
and three non-primitive unique attributes:
Manufacturer Model: m1
User Model: u1
Product Model: p1. It also contains unique attributes:
CatalogVersion Model: Online. It also contains unique attributes
Catalog Model: hwcatalog
Currency Model: currency1
The generated URL is as follows:
The longest nested relation path for attributes of the instance of a Model is added to the URL path. Other non-primitive attributes are added as query parameters. In the
example above you may notice that some resources are accessible by using a unique member from the parent resource and from query parameter at the same time.
Only one query parameter is created in order to pass unique attributes to the speci ed resources. The query parameter consists of:
um__ pre x at the beginning of the query
__ separates pairs of types
, separates pairs of values
Key pairs toType ; fromType, for example: car;user
Values for key pairs valueToType ; valueFromType, for example: c1;u1
The query parameter is generated only if more than one unique attribute has to be passed to the speci c resource. It may include a variety of unique attributes of various
resources. If the resource has one unique attribute, no query parameter is added to the URL.
When an instance of a parent resource is not available, then the proper error message is displayed, for example:
The StagedDD instance of CatalogVersion type not recognized or not available to logged-in user.
The message means that either StagedDD does not exist in CatalogVersion or logged-in user does not have proper read rights.
A user can create custom URL and may skip some unique attributes. However, in that case there is a possibility of occurring ambiguities, and then the exception is thrown.
The order of placing unique attributes is also unrestricted.
http://localhost:9001/ws410/rest/products/HW2320-1008
Found 2 results for the given example [ProductModel (<unsaved>)].
Specify the example model in more detail.
Searched with these attributes: {code=HW2320-1008} [AmbiguousIdentifierException]
Creating and Updating Resources
The new generic node factory is provided by SAP Commerce web services and the process of creating and updating can be easily done for all types of resources.
Examples of Updating Resources
Moving a product from Staged catalog version to Online using PUT method:
http://localhost:9001/ws410/rest/catalogs/clothescatalog/catalogversions/Staged/products/CL1100-aaa015x04
<product code="CL1100-aaa015x04">
<catalogVersion version="Online">
<catalog id="clothescatalog"/>
</catalogVersion>
</product>
If Online catalog version does not include this product, the HTTP/1.1 200 OK status is returned. Otherwise, the error message is thrown:
http://localhost:9001/ws410/rest/catalogs/clothescatalog/catalogversions/Staged/products/CL1100-aaa015x04
This is custom documentation. For more information, please visit the SAP Help Portal
103
5/27/2022
Error updating resource with PUT
ambiguous unique keys {catalogVersion=CatalogVersionModel (8796093186649), code=CL1100-aaa015x04}
for model ProductModel (8796094234625) - found 1 item(s) using the same keys [ModelSavingException]
ambiguous unique keys {catalogVersion=CatalogVersionModel (8796093186649), code=CL1100-aaa015x04}
for model ProductModel (8796094234625) - found 1 item(s) using the same keys [InterceptorException]
Examples of Creating Resources
Creating a new product:
http://localhost:9001/ws410/rest/catalogs/clothescatalog/catalogversions/Staged/products/CL1100-aaa015x04
<product code="CL1100-aaa015x04">
</product>
All required unique attributes are taken from the URL.
User can also create a product by specifying URL. Some unique attributes can be passed by input DTO itself. In this case, user does not get any error noti cation.
http://localhost:9001/ws410/rest/catalogs/clothescatalog/catalogversions/Staged/products/CL1100-aaa015x04
<product code="CL1100-aaa015x04">
<catalogVersion version="Online">
<catalog id="hwcatalog"/>
</catalogVersion>
</product>
The product with code CL1100-aaa015x04 is created, and at the same time the catalog version is changed. The product is now accessible only from hwcatalog/Online and
not from clothescatalog/Staged.
Possible Con guration Options
You may use in unique primitive attributes of a Model characters that are reserved for unique query parameters in the SAP Commerce web services. For this reason, it is
possible to con gure special characters in the query parameter by changing the project.properties le:
project.properties
#########################################
#Query parameters within url generation configuration
#########################################
#real example: ?um__car;manufacturer__car;user=c2;m1,c2;dkaufmann
webservices.queryparameters.prefix=um
webservices.queryparameters.pairseparator=;
webservices.queryparameters.key.separator=__
webservices.queryparameters.value.separator=,
Veri cation of Query Parameters
While performing the request for a resource, the veri cation of the following query parts of the URL is performed:
Key pairs and their values are checked
Separators are checked
Types are checked
An example of the correct URL:
http://localhost:9001/ws410/rest/catalogs/clothescatalog/catalogversions/Staged/variantproducts/301251/cars/c1?
um__car;address__car;manufacturer__car;user=c1;8796093087767,c1;m1,c1;bpoweronoff
Key Pairs and Key Values
A query parameter with the um__ pre x has to contain a key and its value.
http://localhost:9001/ws410/rest/catalogs/clothescatalog/catalogversions/Staged/variantproducts/301251/cars/c1?um__ ;
Provide key for query parameter with: um__ prefix. [BadRequestException]
http://localhost:9001/ws410/rest/catalogs/clothescatalog/catalogversions/Staged/variantproducts/301251/cars/c1?
um__car;address__car;manufacturer__car;user=
Provide value for query parameter with: um__ prefix. [BadRequestException]
This is custom documentation. For more information, please visit the SAP Help Portal
104
5/27/2022
Separators
http://localhost:9001/ws410/rest/catalogs/clothescatalog/catalogversions/Staged/variantproducts/301251/cars/c1?
um__caraddress__car;manufacturer__car;user=c1;8796093087767,c1;m1,c1;bpoweronoff
Only one pair separator: ';' is allowed within query parameter key which represents types.
Within query parameter from URL:
http://localhost:9001/ws410/rest/catalogs/clothescatalog/catalogversions/Staged/variantproducts/
301251/cars/c1?um__caraddress__car;manufacturer__car;user=c1;8796093087767,c1;m1,c1;bpoweronoff
the caraddress element is invalid! [BadRequestException]
http://localhost:9001/ws410/rest/catalogs/clothescatalog/catalogversions/Staged/variantproducts/301251/cars/c1?
um__car;address__car;manufacturer__car;user=c1;8796093087767,c1;m1,c1bpoweronoff
Only one pair separator: ';' is allowed within query parameter value which represents unique value of the
specified type. Within query parameter from URL:
http://localhost:9001/ws410/rest/catalogs/clothescatalog/catalogversions/Staged/variantproducts/
301251/cars/c1?um__car;address__car;manufacturer__car;user=c1;8796093087767,c1;m1,c1bpoweronoff
the c1bpoweronoff element is invalid! [BadRequestException]
Types
http://localhost:9001/ws410/rest/catalogs/clothescatalog/catalogversions/Staged/variantproducts/301251/cars/c1?
um__caRR;address__car;manufacturer__car;user=c1;8796093087767,c1;m1,c1;bpoweronoff
Such caRR;address unique attribute is incorrect and is not taken into account. It means that car c1 will be searched without unique address attribute.
http://localhost:9001/ws410/rest/catalogs/clothescatalog/catalogversions/Staged/variantproducts/301251/cars/c1?
um__car;addressZZ__car;manufacturer__car;user=c1;8796093087767,c1;m1,c1;bpoweronoff
Within query parameter from URL:
http://localhost:9001/ws410/rest/catalogs/clothescatalog/catalogversions/Staged/variantproducts/
301251/cars/c1?um__car;addressZZ__car;manufacturer__car;user=c1;8796093087767,c1;m1,c1;bpoweronoff
the car;addressZZ element is invalid because the resource with type:
addressZZ is not a unique member of the resource with type: car [BadRequestException]
Example of Generated URLs for a Product Resource
The example below presents generating unique URLs for a complex Product resource:
http://localhost:9001/ws410/rest/catalogs/clothescatalog/catalogversions/Staged/products/CL1100-aaa015x04
<product code="CL1100-aaa015x04" pk="8796094234625"
uri="http://localhost:9001/ws410/rest/catalogs/clothescatalog/catalogversions/Staged/products/CL1100-aaa015x04"
xmlns:ns2="http://research.sun.com/wadl/2006/10">
<comments/>
<creationtime>2010-12-02T11:29:39+01:00</creationtime>
<modifiedtime>2010-12-02T11:29:53+01:00</modifiedtime>
<approvalStatus>approved</approvalStatus>
<cars/>
<catalogVersion version="Staged" pk="8796093219417"
uri="http://localhost:9001/ws410/rest/catalogs/clothescatalog/catalogversions/Staged"/>
<classificationClasses/>
<data_sheet/>
<description>Jeans with appliqué yoke to front and back,
two pockets to the back and two fly pockets to the front.
Slight bootcut,roughly 32.5" in length, 100% cotton.</description>
<detail/>
<ean>CL1100-aaa015x04</ean>
<europe1Discounts/>
<europe1Prices/>
<europe1Taxes/>
<features/>
<logo/>
<manufacturerName>Bei Ling Inc.</manufacturerName>
<name>Classic jeans</name>
<normal/>
<others/>
<picture downloadURL="/medias/sys_master/8796137979934/aaa015x04_middle.jpg?mime=image%2Fjpeg&realname=aaa015x04_middle.jpg"
code="aaa015x04_middle" pk="8796137947166" uri="http://localhost:9001/ws410/rest/catalogs/clothescatalog/catalogversions/Staged/me
<priceQuantity>1.0</priceQuantity>
<productReferences/>
<stock/>
<supercategories>
<category code="CL1100" pk="8796093612174" uri="http://localhost:9001/ws410/rest/catalogs/clothescatalog/catalogversions/Stage
<category code="topseller" pk="8796093808782" uri="http://localhost:9001/ws410/rest/catalogs/clothescatalog/catalogversions/St
</supercategories>
<thumbnail downloadURL="/medias/sys_master/8796138045470/aaa015x04_thumbnail.jpg?mime=image%2Fjpeg&realname=aaa015x04_thumbnai
code="aaa015x04_thumbnail" pk="8796138012702" uri="http://localhost:9001/ws410/rest/catalogs/clothescatalog/catalogversions/Staged
<thumbnails/>
<unit code="pieces" pk="8796093054986" uri="http://localhost:9001/ws410/rest/units/pieces"/>
<untypedFeatures/>
This is custom documentation. For more information, please visit the SAP Help Portal
105
5/27/2022
<variantType code="Jeans" pk="8796108488786" uri="http://localhost:9001/ws410/rest/varianttypes/Jeans"/>
<variants>
<variantProduct code="CL1100-aaa015x04-00" pk="8796100067329"
uri="http://localhost:9001/ws410/rest/catalogs/clothescatalog/catalogversions/Staged/variantproducts/CL1100-aaa015x04-00"/>
<variantProduct code="CL1100-aaa015x04-01" pk="8796100100097"
uri="http://localhost:9001/ws410/rest/catalogs/clothescatalog/catalogversions/Staged/variantproducts/CL1100-aaa015x04-01"/>
<variantProduct code="CL1100-aaa015x04-02" pk="8796100132865"
uri="http://localhost:9001/ws410/rest/catalogs/clothescatalog/catalogversions/Staged/variantproducts/CL1100-aaa015x04-02"/>
</variants>
</product>
Web Service API - Extended Collection
The Web Service Extended Collection API allows you to control the range of information that is returned by a web service. All resources exposing collections of other
resources support a common set of additional query parameters in order to limit results returned by the resource.
Description
If a resource exposed by a web service returns a collection of elements (root resource) or has collection properties that return a collection of elements (non-root resource),
you can use query parameters to restrict the number of elements returned, by using a set of speci ed parameters. The following parameters are allowed: sorting attribute,
size of a page, number of a page, a subtypes and a query. Collection properties that originate from CollectionTypes have a limited number of query parameters and you can
use only: sorting attribute, size of a page and number of a page.
Use of the mechanism, called paging, allows client to shorten response times by reducing the amount of information transferred by web services.
It may also reduce the load of the Commerce Platform server (however, current implementation has limitations - see the Hints section below).
Query Parameters
Schema for the query parameters is consistent for different kinds of resources (root or non-root resources) and allows paging of several distinct collection properties in a
single request. It is possible, because names of query parameters are different for each collection.
There are ve parameters that can be used for paging of a collection property:COLNAME_page,COLNAME_size,COLNAME_sort,COLNAME_subtypes and COLNAME_query.
All of them are allowed for collection properties that originate from RelationTypes. However the last two are not allowed for collection properties that originate from
CollectionTypes.COLNAME denotes the collection name.
1. COLNAME_sort determines sorting order of the collection elements. It accepts property name and the asc or desc suffix that speci es sorting direction. The default
value is asc.
2. COLNAME_size determines size of a page. It accepts integer values and the default is 20. You can override the default value by changing it in project.properties
le in the platformwebservices extension:
project.properties
...
# if property is not set then default_page_size is set to 20
webservices.paging.default_page_size=15
...
To receive all elements, set the size of a page to -1.
3. COLNAME_page determines number of a page to return. It accepts integer values and starts from 0 ( rst page).
4. COLNAME_subtypes determines whether subtypes of a speci ed collection element type is taken into account. By default all subtypes are included COLNAME_subtypes=true.
5. COLNAME_query determines parameters of the WHERE statement for a FlexibleSearch query. When the paging mode is used, the FlexibleSearch query is generated
to obtain the speci ed collection. The URL-safe encoding representation is required, for example {name} LIKE '%abc%' should look
like:COLNAME_query=%7Bname%7D%20LIKE%20'%25abc%25'. This query returns elements with names that satisfy the speci ed condition.
COLNAME is the XML tag name of the collection that you wish to page. It may be:
A name of the root tag in output XML le, that is received as the query result for a root resource. For example http:// platformwebservices-url /catalogs
resource returns a collection of catalog elements. Thus the collection name is catalogs.
http://localhost:9001/ws410/rest/catalogs
<catalogs>
<catalog uri="http://localhost:9001/ws410/rest/catalogs/Default"
id="Default"/>
<catalog uri="http://localhost:9001/ws410/rest/catalogs/hwcatalog"
id="hwcatalog"/>
<catalog uri="http://localhost:9001/ws410/rest/catalogs/clothescatalog"
id="clothescatalog"/>
<catalog uri="http://localhost:9001/ws410/rest/catalogs/SampleClassification"
id="SampleClassification"/>
</catalogs>
A name of the collection property of a resource in the output XML le. For example http:// platformwebservices-url /catalogs/clothescatalog/Online
resource has categories collection property, which value is a collection of category elements. Thus the collection name is categories
http://localhost:9001/ws410/rest/catalogs/clothescatalog/Online
This is custom documentation. For more information, please visit the SAP Help Portal
106
5/27/2022
<catalogversion version="Online">
<catalog uri="http://localhost:9001/ws410/rest/catalogs/hwcatalog" id="hwcatalog"/>
<categories>
<category uri="http://localhost:9001/ws410/rest/catalogs/hwcatalog/Online/categories/HW1000"
code="HW1000"/>
<category uri="http://localhost:9001/ws410/rest/catalogs/hwcatalog/Online/categories/HW2000"
code="HW2000"/>
<category uri="http://localhost:9001/ws410/rest/catalogs/hwcatalog/Online/categories/topseller"
code="topseller"/>
<category uri="http://localhost:9001/ws410/rest/catalogs/hwcatalog/Online/categories/specialoffers"
code="specialoffers"/>
</categories>
</catalogversion>
 Note
Property name and sorting direction should be separated by a space. However spaces in URL are encoded as + characters, so they should be provided in the following
way:COLNAME_sort=name+desc or COLNAME_sort=name+asc.
Paging and Security
The paging mechanism is based on the FlexibleSearch functionality. It delivers more exible searching and more efficient paging of large collections. First the paginated
result is prepared and then the security layer checks user rights for each element. Then a subset of paginated results is returned.
This could cause a random number of elements per page, between 0 to COLNAME_size. We allow you to customize the behavior by con guring the property in the
project.properties le in the platformwebservices extension:
project.properties
...
webservices.paging.complete_size_per_page=true
...
If this property is set to true, the number of elements returned per each page is equal to COLNAME_size, assuming that the current page is not the last one. The result may
include elements, to which the user does not have rights. However all attributes of such elements are invisible for the user.
Otherwise, if the property is set to false, the random number of elements per page may be returned.
Sorting of Collection Elements
To return a page of results, the whole collection is rst sorted to determine the order of elements. Without sorting, paging operation is meaningless. Root collections and
collection properties that originate from RelationTypes, use the FlexibleSearch sorting mechanism. For collection properties that come from CollectionTypes, the sorting
mechanism depends on the type of collection elements. There are two possible situations:
Collection of SAP Commerce Model Instances (Typical Case)
The SAP Commerce model instances, for example catalogs or categories, are not comparable. However they contain properties which values are comparable. Sorting of
collection of some SAP Commerce model instances requires an existing property, which value can be used in comparison. The name of such property is assumed to be the
value of COLNAME_sort parameter.
If no COLNAME_sort parameter is provided, the default property name is pk. Every Model class has the pk property and it can be used for comparisons.
 Note
Resources exposed by the SAP Commerce Web Service API are based on SAP Commerce models, so properties used for sorting are properties of model classes. It is
necessary to sort using only those properties that return comparable values (java.lang.Comparable). Common Java reference types, such as String, Number, Date,
excluding arrays satisfy the requirement.
Collection of Comparable Objects (Special Case)
Another mechanism allows to sort collection property that does not contain the SAP Commerce model, but arbitrary java objects, for example String or Date instances.
Such property can be sorted if all objects in the collection are of the same java type and that type implements java.lang.Comparable.
To sort such a collection the following query parameter should be provided:COLNAME_sort=pk+asc or COLNAME_sort=pk+desc.
It is possible to use instead pk any property name, that does not exist in the element of sorted collection.
If the property given in COLNAME_sort is not found in the collection element, the mechanism tries to use the whole object as a comparable value.
For example, in case of collection of String objects, there is no pk property in the compared String object, so the object itself is used for sorting.String objects implements
java.lang.Comparable so they can be directly compared and thus the whole collection of String objects can be sorted.
Hints
This is custom documentation. For more information, please visit the SAP Help Portal
107
5/27/2022
Potential performance problems:
In the current implementation sorting and paging for collection properties that come from CollectionTypes are executed in application server memory only. No
database features are used. This is due to the fact that is not possible to generate query for them in an automatic way.
As a result, some performance problems may occur if huge collections are paged. In one of the next releases this will be improved.
Lack of information about a total collection size:
The current implementation does not provide the total size of the collection. In one of the next releases of the Webservice API these informations will be part of the
response:
<catalogs page="1" page_size="10" total_size="34">...</catalogs>
Root resource name:
 Note
The URL path to a root resource and the name of a root tag in the output XML le of the resource must be the same.
From the example above:
URL: http:// platformwebservices-url /catalogs
XML root element:catalogs
Sorting property name:
It is technically possible that a property in the Model class e.g.clientSurname is renamed in the output XML le to e.g.lastName. However, if the property is used for
sorting:COLNAME_sort=PropertyName, it is required that the property name is exactly the same in the Model class, in the output XML le and in the query
parameter.
 Note
Important Information for Creators of New Resources
Property names of the Model class may not be changed in the output XML le if the property is used for sorting.
Related Information
Extended Collection API - Examples
Web Service API - Reference
The SAP Commerce Web Service API is a set of HTTP request methods that are available for users to retrieve, post or update an information on a server. This reference
presents examples of resources that may be exposed by using HTTP method. For Cart or CronJobs, additional commands may be applied.
Table Explanation
Request
Method
URL
Body
HTTP method that may be used:
The URL of a resource.
Request content used for modifying a resource. Usually it is
GET
A resource often addresses an item like Catalog, User and
PUT
POST
DELETE
so on, although that is not required. Values in brackets are
placeholders and must be replaced with concrete
identi ers, for example:
useful only for PUT or POST. The given value is always a
java class (DTO) which must be used according the main
type, for example if body is de ned as UserDTO and
service accepts "application/xml" than it has to be rst
transformed into XML.
uri/users/userid
can be resolved as
localhost:9001/ws410/rest/users/democustomer
Response
Result State
Result Body
Description
State of HTTP request's result described by a numerical
Content of a response, that is valid for any HTTP method.
General result description
value, usually 200 OK.
The given value is always a java class (DTO), but the actual
produced content depends on the mime type, for example
for application/xml it returns xml content.
This is custom documentation. For more information, please visit the SAP Help Portal
108
5/27/2022
List of Resources
User And Security
Users
Method
URL
Body
Result State
Result Body
Description
GET
uri/users/
-
200 (OK)
UsersDTO (uid + uri)
Returns a list of all
UserDTOs.
User
Method
URL
Body
Result State
Result Body
GET
uri/users/userid
-
200 (OK)
UserDTO
404 (NOT FOUND)
-
resource not found
200 (OK)
-
successfully updated
201 (CREATED)
-
successfully created
400 (BAD REQUEST)
error message
well formed but not valid
PUT
uri/users/userid
UserDTO
Description
XML, for example missing
mandatory properties
DELETE
uri/users/userid
-
200 (OK)
successfully deleted
404 (NOT FOUND)
resource not found
Customers
Method
URL
Body
Result State
Result Body
Description
GET
uri/customers/
-
200 (OK)
CustomersDTO (uid + uri)
Returns a list of all
CustomerDTOs
Customer
Method
URL
Body
Result State
Result Body
GET
uri/customers/customerid
-
200 (OK)
CustomerDTO
404 (NOT FOUND)
-
resource not found
200 (OK)
-
successfully updated
201 (CREATED)
-
successfully created
400 (BAD REQUEST)
error message
well formed but not valid
PUT
uri/customers/customerid
CustomerDTO
Description
XML, for example missing
mandatory properties
DELETE
uri/customers/customerid
-
200 (OK)
successfully deleted
404 (NOT FOUND)
resource not found
UserGroups
Method
URL
Body
Result State
Result Body
Description
GET
uri/usergroups/
-
200 (OK)
UserGroupsDTO (uid + uri)
Returns a list of all
UserGroupDTOs.
UserGroup
Method
URL
Body
Result State
Result Body
GET
uri/usergroups/groupid
-
200 (OK)
UserGroupDTO
This is custom documentation. For more information, please visit the SAP Help Portal
Description
109
5/27/2022
Method
PUT
URL
uri/usergroups/groupid
Body
UserGroupDTO
Result State
Result Body
Description
404 (NOT FOUND)
-
resource not found
200 (OK)
-
successfully updated
201 (CREATED)
-
successfully created
400 (BAD REQUEST)
error message
well formed but not valid
XML, for example missing
mandatory properties
DELETE
uri/usergroups/groupid
-
200 (OK)
successfully deleted
404 (NOT FOUND)
resource not found
Companies
Method
URL
Body
Result State
Result Body
Description
GET
uri/companies/
-
200 (OK)
CompaniesDTO (uid + uri)
Returns a list of all
CompanyDTOs.
POST
uri/companies/
CompanyDTO
201 (CREATED)
CompanyDTO
successfully created
400 (BAD REQUEST)
error message
well formed but not valid
XML, for example missing
mandatory properties
Company
Method
URL
Body
Result State
Result Body
Description
GET
uri/companies/companyUID
-
200 (OK)
CompanyDTO
use company's uid attribute
value
PUT
uri/companies/companyUID
CompanyDTO
404 (NOT FOUND)
-
resource not found
200 (OK)
-
successfully updated
201 (CREATED)
-
successfully created
400 (BAD REQUEST)
error message
well formed but not valid
XML, for example missing
mandatory properties
DELETE
uri/companies/companyUID
-
200 (OK)
successfully deleted
404 (NOT FOUND)
resource not found
Login
Method
URL
Body
Result State
Result Body
GET
uri/login
-
200 (OK)
Authorization successful
401 (Unauthorized)
Description
Authorization failed because
of wrong credentials
RetrievePassword
Method
URL
GET
uri/retrievepassword/userid
Body
Result State
Result Body
200 (OK)
Text containing password
Description
question
404 (NOT FOUND)
User not found or user has
no password question
de ned
PUT
uri/retrievepassword/userid
UserDTO
200 (OK)
Text containing new
successfully created new
Password or error message
random password or wrong
answer entered
400 (BAD REQUEST)
error message
well formed but not valid
XML, for example missing
mandatory properties
This is custom documentation. For more information, please visit the SAP Help Portal
110
5/27/2022
Method
URL
Body
Result State
Result Body
404 (NOT FOUND)
Description
User not found or user has
no password question
de ned
ChangePassword
Method
URL
Body
Result State
PUT
uri/changepassword
PasswordDTO
200 (OK)
Result Body
Description
successfully created new
password
400 (BAD REQUEST)
error message
well formed but not valid
XML, for example missing
mandatory properties
Addresses
Method
URL
Body
Result State
Result Body
Description
GET
uri/addresses/
-
200 (OK)
AddressesDTO (pk + uri)
Returns a list of all
AddressDTOs.
POST
uri/addresses/
AddressDTO
201 (CREATED)
AddressDTO
successfully created
400 (BAD REQUEST)
error message
well formed but not valid
XML, for example missing
mandatory properties
Address
Method
URL
Body
Result State
Result Body
GET
uri/addresses/pk
-
200 (OK)
AddressDTO
404 (NOT FOUND)
-
resource not found
200 (OK)
-
successfully updated
400 (BAD REQUEST)
error message
well formed but not valid
PUT
uri/addresses/pk
AddressDTO
Description
XML, for example missing
mandatory properties
DELETE
uri/addresses/pk
-
200 (OK)
successfully deleted
404 (NOT FOUND)
resource not found
Catalog Structure and Products
Catalogs
Method
URL
Body
Result State
Result Body
Description
GET
uri/catalogs/
-
200 (OK)
CatalogsDTO (id + uri)
Returns a list of all
CatalogDTOs.
Catalog
Method
URL
Body
Result State
Result Body
GET
uri/catalogs/catalogid
-
200 (OK)
CatalogDTO
404 (NOT FOUND)
PUT
uri/catalogs/catalogid
CatalogDTO
Description
resource not found
200(OK)
-
successfully updated
201 (CREATED)
-
successfully created
400 (BAD REQUEST)
error message
well formed but not valid
XML, for example missing
mandatory properties
This is custom documentation. For more information, please visit the SAP Help Portal
111
5/27/2022
Method
URL
Body
Result State
Result Body
Description
DELETE
uri/catalogs/catalogid
-
200 (OK)
successfully deleted
404 (NOT FOUND)
resource not found
CatalogVersion
Method
URL
Body
Result State
Result Body
GET
uri/catalogs/catalog /catalogversions/version
-
200 (OK)
CatalogVersionDTO
404 (NOT FOUND)
uri/catalogs/catalog /catalogversions/version
PUT
CatalogVersionDTO
Description
resource not found
200(OK)
-
successfully updated
201 (CREATED)
-
successfully created
400 (BAD REQUEST)
error message
well formed but not
valid XML, for example
missing mandatory
properties
uri/catalogs/catalog /catalogversions/version
DELETE
-
200 (OK)
successfully deleted
404 (NOT FOUND)
resource not found
Category
Method
URL
Body
Result State
Result Body
GET
uri/catalogs/catalog /catalogversions/version/categories/category
-
200 (OK)
CategoryDTO
404 (NOT FOUND)
PUT
uri/catalogs/catalog /catalogversions/version/categories/category
CategoryDTO
200 (OK)
Description
resource not found
-
successfully
updated
201 (CREATED)
-
successfully created
400 (BAD
error message
well formed but not
REQUEST)
valid XML, for
example missing
mandatory
properties
DELETE
uri/catalogs/catalog /catalogversions/version/categories/category
-
200 (OK)
successfully deleted
404 (NOT FOUND)
resource not found
Product
Method
URL
Body
Result State
Result Body
GET
uri/catalogs/catalog /catalogversions/version/products/productcode
-
200 (OK)
ProductDTO
404 (NOT FOUND)
PUT
uri/catalogs/catalog /catalogversions/version/products/productcode
ProductDTO
200 (OK)
Description
resource not found
-
successfully
updated
201 (CREATED)
-
successfully
created
400 (BAD
error message
REQUEST)
well formed but not
valid XML, for
example missing
mandatory
properties
DELETE
uri/catalogs/catalog /catalogversions/version/products/productcode
-
200 (OK)
successfully
deleted
404 (NOT FOUND)
resource not found
Units
Method
URL
Body
Result State
Result Body
This is custom documentation. For more information, please visit the SAP Help Portal
Description
112
5/27/2022
Method
URL
Body
Result State
Result Body
Description
GET
uri/units/
-
200 (OK)
UnitsDTO (code + uri)
Returns a list of all
UnitDTOs.
Unit
Method
URL
Body
Result State
Result Body
GET
uri/units/unitcode
-
200 (OK)
UnitDTO
404 (NOT FOUND)
-
resource not found
200 (OK)
-
successfully updated
201 (CREATED)
-
successfully created
400 (BAD REQUEST)
error message
well formed but not valid
PUT
uri/units/unitcode
UnitDTO
Description
XML, for example missing
mandatory properties
DELETE
uri/units/unitcode
-
200 (OK)
successfully deleted
404 (NOT FOUND)
resource not found
Ordering Process
Currencies
Method
URL
Body
Result State
Result Body
Description
GET
uri/currencies/
-
200 (OK)
CurrenciesDTO (isocode +
Returns a list of all
uri)
CurrencyDTOs.
Description
Currency
Method
URL
Body
Result State
Result Body
GET
uri/currencies/isocode
-
200 (OK)
CurrencyDTO
404 (NOT FOUND)
-
resource not found
200 (OK)
-
successfully updated
201 (CREATED)
-
successfully created
400 (BAD REQUEST)
error message
well formed but not valid
PUT
uri/currencies/isocode
CurrencyDTO
XML, for example missing
mandatory properties
DELETE
uri/currencies/isocode
-
200 (OK)
successfully deleted
404 (NOT FOUND)
resource not found
Discounts
Method
URL
Body
Result State
Result Body
Description
GET
uri/discounts/
-
200
DiscountsDTO (code + uri)
Returns a list of all
DiscountDTOs.
Discount
Method
URL
Body
Result State
Result Body
GET
uri/discounts/code
-
200 (OK)
DiscountDTO
404 (NOT FOUND)
-
resource not found
200 (OK)
-
successfully updated
201 (CREATED)
-
successfully created
PUT
uri/discounts/code
DiscountDTO
This is custom documentation. For more information, please visit the SAP Help Portal
Description
113
5/27/2022
Method
URL
Body
Result State
Result Body
Description
400 (BAD REQUEST)
error message
well formed but not valid
XML, for example missing
mandatory properties
uri/discounts/code
DELETE
-
200 (OK)
successfully deleted
404 (NOT FOUND)
resource not found
Carts
Method
URL
Body
Result State
Result Body
Description
GET
uri/carts/
-
200 (OK)
CartsDTO (pk + uri)
Returns a list of all
CartDTOs.
uri/carts/
POST
CartDTO
201 (CREATED)
CartDTO
successfully created
400 (BAD REQUEST)
error message
well formed but not valid
XML, for example missing
mandatory properties
Cart
Carts are identi ed using a pk property. To access a speci c cart you need to specify the cart's pk.
Method
URL
Body
Result State
Result Body
GET
uri/carts/code
-
200 (OK)
CartDTO
404 (NOT FOUND)
-
resource not found
200 (OK)
-
successfully updated
201 (CREATED)
-
successfully created
400 (BAD REQUEST)
error message
well formed but not valid
uri/carts/code
PUT
CartDTO
Description
XML, for example missing
mandatory properties
uri/carts/code
DELETE
-
200 (OK)
successfully deleted
404 (NOT FOUND)
resource not found
Cart Commands
Command
Method
URL
Body
Parameter
Result State
Result Body
Description
PlaceOrderCommand
POST
uri/carts/code?
cmd=PlaceOrderCommand
CartDTO
-
200 (OK)
-
placing order
400 (BAD
error message
the appropriate
REQUEST)
error message
CartEntries
GET
uri/carts/cartcode/cartentries
-
200 (OK)
CartEntriesDTO (pk + uri)
Returns a list of all
CartEntryDTOs.
POST
uri/carts/cartcode/cartentries
CartEntryDTO
201 (CREATED)
CartEntryDTO
successfully created
400 (BAD REQUEST)
error message
well formed but not valid
XML, for example missing
mandatory properties
CartEntry
Method
URL
Body
Result State
Result Body
GET
uri/carts/cartcode/cartentries/pk
-
200 (OK)
CartEntryDTO
404 (NOT FOUND)
-
resource not found
200 (OK)
-
successfully updated
PUT
uri/carts/cartcode/cartentries/pk
CartEntryDTO
This is custom documentation. For more information, please visit the SAP Help Portal
Description
114
5/27/2022
Method
URL
Body
Result State
Result Body
Description
201 (CREATED)
-
successfully created
400 (BAD REQUEST)
error message
well formed but not valid
XML, for example missing
mandatory properties
DELETE
uri/carts/cartcode/cartentries/pk
-
200 (OK)
successfully deleted
404 (NOT FOUND)
resource not found
PaymentInfos
Method
URL
Body
Result State
Result Body
Description
GET
uri/paymentinfos/
-
200 (OK)
PaymentInfosDTO
Returns a list of all
PaymentInfoDTOs.
GET
uri/debitpaymentinfos/
-
200 (OK)
DebitPaymentInfosDTO
Returns a list of all
DebitPaymentInfoDTOs.
POST
uri/debitpaymentinfos/
DebitPaymentInfosDTO
201 (CREATED)
DebitPaymentInfoDTO
successfully created
400 (BAD REQUEST)
error message
well formed but not valid
XML, for example missing
mandatory properties
GET
uri/creditcardpaymentinfos/
-
200 (OK)
CreditCardPaymentInfosDTO
Returns a list of all
CreditCardPaymentInfoDTOs.
POST
uri/creditcardpaymentinfos/
CreditCardPaymentInfosDTO
201 (CREATED)
CreditCardPaymentInfoDTO
successfully created
400 (BAD REQUEST)
error message
well formed but not valid
XML, for example missing
mandatory properties
GET
uri/advancepaymentinfos/
-
200 (OK)
AdvancePaymentInfosDTO
Returns a list of all
AdvancePaymentInfoDTOs.
POST
uri/advancepaymentinfos/
AdvancePaymentInfosDTO
201 (CREATED)
AdvancePaymentInfoDTO
successfully created
400 (BAD REQUEST)
error message
well formed but not valid
XML, for example missing
mandatory properties
GET
uri/invoicepaymentinfos/
-
200 (OK)
InvoicePaymentInfosDTO
Returns a list of all
InvoicePaymentInfoDTOs.
POST
uri/invoicepaymentinfos/
InvoicePaymentInfosDTO
201 (CREATED)
InvoicePaymentInfoDTO
successfully created
400 (BAD REQUEST)
error message
well formed but not valid
XML, for example missing
mandatory properties
PaymentInfo
Method
URL
Body
Result State
Result Body
GET
uri/debitpaymentinfos/pk
-
200 (OK)
DebitPaymentInfoDTO
404 (NOT FOUND)
-
resource not found
200 (OK)
-
successfully updated
201 (CREATED)
-
successfully created
400 (BAD REQUEST)
error message
well formed but not valid
PUT
uri/debitpaymentinfos/pk
DebitPaymentInfoDTO
Description
XML, for example missing
mandatory properties
DELETE
GET
PUT
uri/debitpaymentinfos/pk
uri/creditcardpaymentinfos/pk
uri/creditcardpaymentinfos/pk
-
-
CreditCardPaymentInfoDTO
200 (OK)
successfully deleted
404 (NOT FOUND)
resource not found
200 (OK)
CreditCardPaymentInfoDTO
404 (NOT FOUND)
-
resource not found
200 (OK)
-
successfully updated
201 (CREATED)
-
successfully created
This is custom documentation. For more information, please visit the SAP Help Portal
115
5/27/2022
Method
URL
Body
Result State
Result Body
Description
400 (BAD REQUEST)
error message
well formed but not valid
XML, for example missing
mandatory properties
uri/creditcardpaymentinfos/pk
DELETE
-
uri/advancepaymentinfos/pk
GET
-
uri/advancepaymentinfos/pk
PUT
AdvancePaymentInfoDTO
200 (OK)
successfully deleted
404 (NOT FOUND)
resource not found
200 (OK)
AdvancePaymentInfoDTO
404 (NOT FOUND)
-
resource not found
200 (OK)
-
successfully updated
201 (CREATED)
-
successfully created
400 (BAD REQUEST)
error message
well formed but not valid
XML, for example missing
mandatory properties
uri/advancepaymentinfos/pk
DELETE
-
uri/invoicepaymentinfos/pk
GET
-
uri/invoicepaymentinfos/pk
PUT
InvoicePaymentInfoDTO
200 (OK)
successfully deleted
404 (NOT FOUND)
resource not found
200 (OK)
InvoicePaymentInfoDTO
404 (NOT FOUND)
-
resource not found
200 (OK)
-
successfully updated
201 (CREATED)
-
successfully created
400 (BAD REQUEST)
error message
well formed but not valid
XML, for example missing
mandatory properties
uri/invoicepaymentinfos/pk
DELETE
-
200 (OK)
successfully deleted
404 (NOT FOUND)
resource not found
PaymentModes
Method
URL
Body
Result State
Result Body
Description
GET
uri/paymentmodes/
-
200
PaymentModesDTO (code +
Returns a list of all
uri)
PaymentModeDTOs.
PaymentMode
Method
URL
Body
Result State
Result Body
GET
uri/paymentmodes/paymentmode
-
200 (OK)
PaymentModeDTO
404 (NOT FOUND)
-
resource not found
200 (OK)
-
successfully updated
...
-
creating a new type is
PUT
uri/paymentmodes/paymentmode
PaymentModeDTO
Description
currently unavailable [jira:
DEL-209]
400 (BAD REQUEST)
error message
well formed but not valid
XML, for example missing
mandatory properties
DELETE
uri/paymentmodes/paymentmode
-
200 (OK)
successfully deleted
404 (NOT FOUND)
resource not found
DeliveryModes
Method
URL
Body
Result State
Result Body
Description
GET
uri/deliverymodes/
-
200 (OK)
DeliveryModesDTO (code +
Returns a list of all
uri)
DeliveryModeDTOs.
DeliveryMode
This is custom documentation. For more information, please visit the SAP Help Portal
116
5/27/2022
Method
URL
Body
Result State
Result Body
GET
uri/deliverymodes/deliverymode
-
200 (OK)
DeliveryModeDTO
404 (NOT FOUND)
-
resource not found
200 (OK)
-
successfully updated
201 (CREATED)
-
successfully created
400 (BAD REQUEST)
error message
well formed but not valid
PUT
uri/deliverymodes/deliverymode
DeliveryModeDTO
Description
XML, for example missing
mandatory properties
DELETE
uri/deliverymodes/deliverymode
-
200 (OK)
successfully deleted
404 (NOT FOUND)
resource not found
Country, Region, Locale
Countries
Method
URL
Body
Result State
Result Body
Description
GET
uri/countries/
-
200 (OK)
CountriesDTO (isocode +
Returns a list of all
uri)
CountryDTOs.
Description
Country
Method
URL
Body
Result State
Result Body
GET
uri/countries/isocode
-
200 (OK)
CountryDTO
404 (NOT FOUND)
-
resource not found
200 (OK)
-
successfully updated
201 (CREATED)
-
successfully created
400 (BAD REQUEST)
error message
well formed but not valid
PUT
uri/countries/isocode
CountryDTO
XML, for example missing
mandatory properties
DELETE
uri/countries/isocode
-
200 (OK)
successfully deleted
404 (NOT FOUND)
resource not found
Regions
Method
URL
Body
Result State
Result Body
Description
GET
uri/regions/
-
200 (OK)
RegionsDTO (isocode + uri)
Returns a list of all
RegionDTOs.
Region
Method
URL
Body
Result State
Result Body
GET
uri/regions/isocode
-
200 (OK)
RegionDTO
404 (NOT FOUND)
-
resource not found
200 (OK)
-
successfully updated
201 (CREATED)
-
successfully created
400 (BAD REQUEST)
error message
well formed but not valid
PUT
uri/regions/isocode
RegionDTO
Description
XML, for example missing
mandatory properties
DELETE
uri/regions/isocode
-
200 (OK)
successfully deleted
404 (NOT FOUND)
resource not found
Languages
This is custom documentation. For more information, please visit the SAP Help Portal
117
5/27/2022
Method
URL
Body
Result State
Result Body
Description
GET
uri/languages/
-
200 (OK)
LanguagesDTO (isocode +
Returns a list of all
uri)
LanguageDTOs.
Description
Language
Method
URL
Body
Result State
Result Body
GET
uri/languages/isocode
-
200 (OK)
LanguageDTO
404 (NOT FOUND)
-
resource not found
200 (OK)
-
successfully updated
201 (CREATED)
-
successfully created
400 (BAD REQUEST)
error message
well formed but not valid
uri/languages/isocode
PUT
LanguageDTO
XML, for example missing
mandatory properties
uri/languages/isocode
DELETE
-
200 (OK)
successfully deleted
404 (NOT FOUND)
resource not found
Media
Media
Method
URL
Body
Result State
Result Body
GET
uri/catalogs/catalog /catalogversions/version/medias/mediacode
-
200 (OK)
MediaDTO
404 (NOT FOUND)
PUT
uri/catalogs/catalog /catalogversions/version/medias/mediacode
MediaDTO
Description
resource not found
200 (OK)
-
successfully updated
201 (CREATED)
-
successfully created
400 (BAD
error message
well formed but not
REQUEST)
valid XML, for
example missing
mandatory
properties
DELETE
uri/catalogs/catalog /catalogversions/version/medias/mediacode
-
200 (OK)
successfully deleted
404 (NOT FOUND)
resource not found
Media Content - Image Streaming
The PUT and POST methods for media resource enable to send for example a picture on a server.
Method
URL
Body
Result State
Result Body
Description
PUT
uri/catalogs/catalog /catalogversions/version/medias/mediacode/data
InputStream
200 (OK)
-
successfully sent
POST
uri/catalogs/catalog /catalogversions/version/medias/mediacode/data
InputStream
200 (OK)
-
successfully sent
Enumeration
EnumerationMetaTypes
Method
URL
Body
Result State
Result Body
Description
GET
uri/enumerationmetatypes/
-
200
EnumerationTypesDTO
Returns a list of all
(code + uri)
enumeration types
EnumerationMetaType
Method
URL
Body
Result State
Result Body
This is custom documentation. For more information, please visit the SAP Help Portal
Description
118
5/27/2022
Method
URL
Body
Result State
Result Body
Description
GET
uri/enumerationmetatypes/enumtype
-
200 (OK)
EnumerationTypeDTO
404 (NOT FOUND)
PUT
uri/enumerationmetatypes/enumtype
EnumerationTypeDTO
resource not found
201 (CREATED)
-
successfully created
400 (BAD REQUEST)
error message
well formed but not valid
XML, for example missing
mandatory properties
DELETE
uri/enumerationmetatypes/enumtype
-
200 (OK)
successfully deleted
404 (NOT FOUND)
resource not found
400 (BAD REQUEST)
error message
removing impossible, for
example enumeration
type has values
EnumerationValue
Method
URL
Body
Result State
Result Body
Description
GET
uri/enumerationmetatypes/enumtype/enumvalue
-
200 (OK)
EnumerationValueDTO
404 (NOT FOUND)
PUT
uri/enumerationmetatypes/enumtype/enumvalue
EnumerationValueDTO
resource not found
201 (CREATED)
-
successfully created
400 (BAD REQUEST)
error message
well formed but not
valid XML, for example
missing mandatory
properties
DELETE
uri/enumerationmetatypes/enumtype/enumvalue
-
200 (OK)
successfully deleted
404 (NOT FOUND)
resource not found
CronJob
CronJobs
Method
URL
Body
Result State
Result Body
Description
GET
uri/cronjobs/
-
200 (OK)
CronJobsDTO (code + uri)
Returns a list of all
CronJobDTOs.
CronJob
Method
URL
Body
Result State
Result Body
GET
uri/cronjobs/code
-
200 (OK)
CronJobDTO
404 (NOT FOUND)
-
resource not found
200 (OK)
-
successfully updated
201 (CREATED)
-
successfully created (not for
PUT
uri/cronjobs/code
CronJobDTO
Description
sub-classes)
400 (BAD REQUEST)
error message
well formed but not valid
XML, for example missing
mandatory properties
DELETE
uri/cronjobs/code
-
200 (OK)
successfully deleted
404 (NOT FOUND)
resource not found
CronJob Commands
Command
Method
URL
Body
Parameter
Result State
This is custom documentation. For more information, please visit the SAP Help Portal
Result Body
Description
119
5/27/2022
Command
Method
URL
Body
CreateCronJobCommand
POST
uri/cronjobs/code?
cmd=CreateCronJobCommand
CronJobDTO with
Parameter
Result State
Result Body
Description
200 (OK)
-
The command
...code=
creates a cronjob
[newCode]
based on current
cronjob.
400 (BAD
error message
REQUEST)
The newCode has
to be set by
parameter.
400 (BAD
error message
REQUEST)
The ambiguous
code of cronjob.
The new code has
to be unique.
StartCronJobCommand
PUT
uri/cronjobs/code?
cmd=StartCronJobCommand
CronJobDTO
...synchronous=false
200 (OK)
-
The command
starts a cronjob.
The Job will be
performed
asynchronous.
...synchronous=true
200 (OK)
-
The command
starts a cronjob.
The Job will be
performed
synchronous.
WebService API - Request Processor Chain
The Request Processor Chain provides the possibility to intercept RESTful calls to resources. It enables the use of information contained in the requests or their responses,
and the performance of logic before or after passing the call on.
The default request-related logic is performed at the end of the chain. For example, when a user sends a request to modify a resource, the chain intercepts the request to
check if the user has access rights to modify the resource. When the logic that checks access rights is performed, the request is then further processed.
Architecture of Request Processor Chain
Chain consists of separate elements, called processors, which contain their own logic, independent on resources. All processors in chain are executed one after another. The
implementation is based on chain-of-responsibility pattern
. It provides an API that can distinguish between different types of requests, and depending on the type it
applies speci c logic. The order of executing processors is con gured in platformwebservices-web-spring.xml le. Chain elements can be added, removed, and
reordered without recompilation.
Figure: Class diagram
Every request for a resource operates on a different instance of DefaultRequestProcessChain. The chain bean instance is injected into a resource during a request. Every
resource extends AbstractResource, and each HTTP request invokes one of methods of AbstractResource:
createGetResponse
createPutResponse
createDeleteReponse
createPostResponse
This is custom documentation. For more information, please visit the SAP Help Portal
120
5/27/2022
The same chain con guration is used for every kind of request. It implies that internally the RequestProcessor implements request-speci c logic if needed. The Request
Processor Chain logic intercepts the internal request processing. Chain processes its elements of type RequestProcessor one after another, in order of Spring declaration.
The processing may be divided into the following stages:
Forward-chain processing: Every doProcess method of RequestProcessor is invoked and the processor decides if to process its successor. A chain is processed
forward if a processor calls doProcess() method. It ends when one of elements stops calling its successor and returns from chain.
Request execution: Logic for a speci c request type is in callback interface RequestExecution. If the forward-chain processing is nished, the execute method of
RequestExecution is called.
Backward-chain processing: For each processor, logic placed after doProcess call is executed after the logic of succeeding processor.
public class ProceedProcessor<RESOURCE> implements RequestProcessor<RESOURCE>
{
@Override
public void doProcess(final RequestProcessor.RequestType type, final Object dto,
final AbstractResponseBuilder<RESOURCE, ?, ?> responseBuilder, final RequestProcessChain chain)
{
//logic before deafult
chain.doProcess();
//'logic after' default chain's execution
}
}
Chain processing can be aborted when a processor does not call doProcess method:
public class AbortProcessor<RESOURCE> implements RequestProcessor<RESOURCE>
{
@Override
public void doProcess(final RequestProcessor.RequestType type, final Object dto,
final AbstractResponseBuilder<RESOURCE, ?, ?> responseBuilder, final RequestProcessChain chain)
{
//place some logic
return;
}
}
Figure: Sequence diagram showing how GET request is processed by a chain with two elements.
Platform Processors
The Commerce Platform contains the following RequestProcessors:
Processor
Description
Noti cationRequestProcessor
Responsible for publishing cluster-wide noti cations on activity of web services. This
processor should be called as the rst one.
AccessGrantRequestProcessor
Responsible for checking access permissions for web services by delegation directly to
underlying isAccessGrantedExterna method for a resource
LastModi cationCacheRequestProcessor
Returns the date of the last modi cation for a GET requested resource.
ETagCacheRequestProcessor
Supports ETag caching for GET requests. Because of its performance impact, it should be
performed only if the LastModi cationCacheRequestProcessor decides that this
calculation is needed.
This is custom documentation. For more information, please visit the SAP Help Portal
121
5/27/2022
The following processors support caching:
LastModi cationCacheRequestProcessor
ETagCacheRequestProcessor
For details see WebService API - Caching Functionality.
The following state diagram presents how a resource request is processed by the chain con gured in the Commerce Platform:
The Spring con guration of the chain and processors implemented in the
Commerce Platform:
platformwebservices-web-spring.xml
<bean id="notificationProcessor"
class="de.hybris.platform.webservices.processor.impl.NotificationRequestProcessor">
<property name="eventActionFactory" ref="actionEventFactory"/>
</bean>
<bean id="accessRightProcessor"
class="de.hybris.platform.webservices.processor.impl.AccessGrantRequestProcessor">
</bean>
<!-- Legacy implementation for a etag based caching -->
<bean id="etagCacheProcessor"
class="de.hybris.platform.webservices.processor.impl.ETagCacheRequestProcessor"/>
<!-- LastModified based caching -->
<bean id="lmCacheProcessor"
class="de.hybris.platform.webservices.processor.impl.LastModificationCacheRequestProcessor"/>
<bean id="requestProcessChain"
class="de.hybris.platform.webservices.processchain.impl.DefaultRequestProcessChain"
scope="prototype">
<property name="processors">
<list value-type="de.hybris.platform.webservices.processor.RequestProcessor">
<ref bean="notificationProcessor" />
<ref bean="accessRightProcessor" />
<ref bean="lmCacheProcessor" />
<ref bean="etagCacheProcessor" />
</list>
</property>
</bean>
Adding a New Processor
A processor implements RequestProcessor, therefore major implementation is placed in doProcess method. Logic within the processor may depend on the type of call: GET,
PUT, POST, or DELETE.
public class SampleRequestProcessor<RESOURCE> implements RequestProcessor<RESOURCE>
{
@Override
public void doProcess(final RequestProcessor.RequestType type, final Object dto,
final AbstractResponseBuilder<RESOURCE, ?, ?> responseBuilder, final RequestProcessChain chain)
{
This is custom documentation. For more information, please visit the SAP Help Portal
122
5/27/2022
log.info("About to call the next element in the chain - can perform logic now");
chain.doProcessNext();
// Calls the next element in the chain (processor or default logic)
log.info("Next element has returned - can perform further logic now");
}
}
To add the processor to chain, add its bean de nition to the ordered list:
platformwebservices-web-spring.xml
<bean id="newProcessor" class="de.hybris.platform.webservices.impl.SampleRequestProcessor" />
<bean id="requestProcessChain" class="de.hybris.platform.webservices.impl.RequestProcessChainImpl" >
<property name="processors">
<list>
<ref bean="notificationProcessor" />
<ref bean="accessRightProcessor" />
<ref bean="newProcessor" />
....
</list>
</property>
</bean>
WebService API - Security Architecture
The security mechanism underlying the SAP Commerce WebService API is based upon Spring's widely adopted and stable security framework. This ensures a consistent
approach with the rest of SAP Commerce security architecture, which is also based upon Spring.
The main features of the web service security framework include:
Strategy-based framework allowing partners to intuitively select from differing SAP Commerce security strategies or to use their own
Only authenticated and authorized RESTful calls are processed
When data is requested via a RESTful call, only the data to which the caller has Read access is returned. The granularity at which this can be determined is at the
resource and resource-attribute level. For example a user is able to see only attributes A and B of resource R.
When a RESTful call attempts to modify data, only data to which the user has Change access, is modi ed.
If security exceptions is caught or thrown by the security framework, meaningful responses are sent back to the client.
Security Strategies
The web service security framework implements the strategy pattern, allowing the user to select from a set of security strategies that currently include:
Access Manager Security Strategy - based upon the HMC security paradigm
Property File Security Strategy - based upon con guration provided in a properties le
Custom Security Strategy - allowing the user to write their own strategy
 Note
User Group for Web Services
By default the Access Manager Security Strategy is adopted, which authorises a user only if they are in a new security group named webservicegroup. This is not set up
by default, so be sure to create this group for your RESTful calls to be authorised as discussed below.
Each strategy implements the SecurityStrategy interface:
public interface SecurityStrategy
{
boolean isResourceOperationAllowed(final RestResource resource, final String operation);
boolean isResourceCommandAllowed(final RestResource resource, final String command);
boolean isDtoOperationAllowed(final Class<?> objectClass, final String operation);
boolean isAttributeOperationAllowed(final Class<?> attrObjectClass, final String attrQualifier, final String attrOperation);
}
However both strategies differ in implementations and intentions. To specify which strategy to adopt, modify the securityStrategy entry in the platformwebservices-
web-spring.xml le:
platformwebservices-web-spring.xml
<beans>
<!-- ... --->
<bean id="securityStrategy"
class="de.hybris.platform.webservices.AccessManagerSecurityStrategy"
scope="prototype" parent="abstractSecurityStrategy"/>
<!-- <bean id="securityStrategy"
class="de.hybris.platform.webservices.PropertyFileSecurityStrategy"
scope="prototype" parent="abstractSecurityStrategy"/> -->
<!-- <bean id="securityStrategy"
This is custom documentation. For more information, please visit the SAP Help Portal
123
5/27/2022
class="de.hybris.platform.webservices.CustomSecurityStrategy" scope="prototype"
parent="abstractSecurityStrategy"/>--->
<!-- ... --->
<bean id="abstractBaseResource"
class="de.hybris.platform.webservices.AbstractResource" abstract="true"
scope="prototype">
<!-- ... --->
<property name="securityStrategy" ref="securityStrategy"/>
</bean>
</beans>
 Tip
If you wish to disable security mechanisms for any reason, it is enough to remove securityStrategy property from the abstractBaseResource bean.
Below we consider the various strategies, starting with the default: Access Manager Security Strategy.
Access Manager Security Strategy
The Access Manager Security Strategy is the default strategy adopted by the SAP Commerce WebService API and uses the HMC Access Rights approach.
The Access Manager Security Strategy authorises a user only if they are in a security group named webservicegroup. This is not set up by default, so please be sure to
create this group as discussed below, for your RESTful calls to be accepted. The name of this user group is con gurable in project.properties le:
webservices.security.group=webservicegroup
By default three user groups are members of this group:
admingroup
employeegroup
customergroup
If webservicegroup is not de ned as a HMC user group, the user is not allowed to access any resources. For more on access rights, see hMC Access Rights.
In RESTful communication, the mapping between the HTTP methods and CRUD operations are as follows:
HTTP method
CRUD operation
GET
Read
POST
Create / Update
PUT
Create / Update
DELETE
Delete
As seen, both POST and PUT may refer to Create and Update operations. To determine which is meant, when a POST or PUT request is processed, we check if the
referenced resource already exists or not. The following situations are possible:
If the referenced resource does not exist, it is necessary to check if the user has the right to create instances of the corresponding type.
Ff the referenced resource does exist, it is necessary to check if the user has the right to update instances of the corresponding type.
The central management of access rights to each type and its attributes is located within the Hybris Management Console:
This is custom documentation. For more information, please visit the SAP Help Portal
124
5/27/2022
The type-based web services security con guration managed in HMC is divided into two basic steps:
1. Resource (type) level security
2. Attribute level security, which also contains the type level security
For resource level it is possible to set Read, Change, Create and Delete rights. For attribute level security, only the Read and Change rights may be set.
If a user does not have the right to a speci ed operation on a requested resource, the following message appears:
You do not have permission to request this resource ( resource name ) using HTTP_method method.
Type level security is included in attribute level security checking. If any operation is not allowed for the speci ed attribute type, the user receives the message:
You do not have permission to CRUD operation: DTOclassName dto.
If a user has no Read rights for a certain attribute of the requested resource, this attribute is excluded from the response. If a user tries to update an attribute, which he is
not allowed to change, the attribute is not modi ed and the HTTP status code Forbidden (403) is sent with the message:
You do not have permission to change list_of_attributes attributes of the DTOclassName dto.
If a user has Change right to some, but not all attributes of a resource and tries to update all of them, none of them are updated. In this case the user should remove not
allowed attributes from the request.
If a user requests a resource and has Read access to some, but not all attributes of the requested resource, then those unavailable attributes are not included in the XML
response.
Examples
User A has all access rights.
MyLanguage resource extends Language resource.
Type
Attribute
Read
Change
Create
Delete
Language
MyLanguage
Method
URL
Result
GET
/languages
List of all Language instances, but without MyLanguage
instances.
GET
/languages/de
Details of de language.
GET
/mylanguages/myde
HTTP status code Forbidden (403) informing that the user
does not have sufficient rights to execute the requested
operation.
PUT/POST
/languages/de
If the referenced de language exists, it is updated.
Otherwise it is created.
DELETE
/languages/de
Delete de language.
User B has only Read right.
Type
Attribute
Read
Change
Create
Delete
Language
Method
URL
Result
PUT/POST
/languages/de
HTTP status code Forbidden (403) informing that the user
does not have sufficient rights to execute the requested
operation.
DELETE
/languages/de
HTTP status code Forbidden (403) informing that the user
does not have sufficient rights to execute the requested
operation.
User C is not allowed to update Language resource.
Type
Attribute
Read
Change
Create
Delete
Language
Method
URL
Result
This is custom documentation. For more information, please visit the SAP Help Portal
125
5/27/2022
Method
URL
Result
PUT/POST
/languages/de
If the referenced language does no exist, it is created.
If the referenced language exists, the request results in
HTTP status code Forbidden (403), informing that the user
does not have sufficient rights to execute update operation.
User D has no rights for Language resource.
Type
Attribute
Read
Change
Create
Delete
Language
Method
URL
Result
GET
/languages
Empty list, as user D has no Read access to language
instances.
GET
/languages/de
HTTP status code Forbidden (403) informing that the user
does not have sufficient rights to execute the requested
operation.
PUT/POST
/languages/de
HTTP status code Forbidden (403) informing that the user
does not have sufficient rights to execute the requested
operation.
DELETE
/languages/de
HTTP status code Forbidden (403) informing that the user
does not have sufficient rights to execute the requested
operation.
User A has all rights.
Type
Attribute
Read
Change
Create
Delete
Language
isocode
name
Method
URL
Result
GET
/languages/de
<language>
<isocode>de</isocode>
<name>German</name>
</language>
User B has no rights to read or update the name attribute.
Type
Attribute
Read
Change
Create
Delete
Language
isocode
name
Method
URL
Result
PUT
/languages/de
Body of the request:
<language>
<isocode>de</isocode>
</language>
PUT
/languages/fr
Body of the request:
<language>
<isocode>fr</isocode>
<name>French</name>
</language>
Results in HTTP status code Forbidden (403) informing that
the user has no rights to change the name attribute.
This is custom documentation. For more information, please visit the SAP Help Portal
126
5/27/2022
Property File Security Strategy
This strategy is based on the con guration project.properties le in the platformwebservices extension. It is a resource level security strategy.
Security Access Roles
Secured resources are given by:
1. key, which addresses single classes or whole packages, similar to log4j
2. value, which is a group or role followed by a list of allowed HTTP methods
Leave value of this property empty or set one or more groups.
Examples:
Global options. The following settings allow speci ed groups access to all resources, however anonymous group may just Read them:
restjersey.security.de=admingroup[GET,PUT,DELETE,POST]
restjersey.security.de.hybris.platform.restjersey.resources=anonymous[GET]
The following settings assign groups to speci ed resources:
restjersey.security.de.hybris.platform.restjersey.resources.CatalogsResource=
anonymous[GET]; customergroup[GET]
restjersey.security.de.hybris.platform.restjersey.resources.CatalogResource=
anonymous[GET]; customergroup[GET]
Examples of Different Con gurations
All use cases for admingroup are presented in the simple example. Results are retrieved using GET method.
Below different available con gurations are presented:
restjersey.security.de.hybris.platform.restjersey.resources=
admingroup[GET,PUT,DELETE,POST]
restjersey.security.de.hybris.platform.restjersey.resources.CatalogsResource=
restjersey.security.de.hybris.platform.restjersey.resources.CatalogResource=
or
restjersey.security.de.hybris.platform.restjersey.resources=
admingroup[GET,PUT,DELETE,POST]
or
restjersey.security.de.hybris.platform.restjersey.resources=
restjersey.security.de.hybris.platform.restjersey.resources.CatalogsResource=
admingroup[GET,PUT,DELETE,POST]
restjersey.security.de.hybris.platform.restjersey.resources.CatalogResource=
admingroup[GET,PUT,DELETE,POST]
or
restjersey.security.de.hybris.platform.restjersey.resources.CatalogsResource=
admingroup[GET,PUT,DELETE,POST]
restjersey.security.de.hybris.platform.restjersey.resources.CatalogResource=
admingroup[GET,PUT,DELETE,POST]
Request
Response
http://localhost:9001/ws410/rest/catalogs/
Retrieves all catalogs
http://localhost:9001/ws410/rest/catalogs/hwcatalog/
Retrieve the speci ed catalog.
restjersey.security.de.hybris.platform.restjersey.resources=
restjersey.security.de.hybris.platform.restjersey.resources.CatalogsResource=
admingroup[GET,PUT,DELETE,POST]
restjersey.security.de.hybris.platform.restjersey.resources.CatalogResource=
employeegroup[GET]
Request
Response
http://localhost:9001/ws410/rest/catalogs/
Retrieves all catalogs
http://localhost:9001/ws410/rest/catalogs/hwcatalog/
HTTP status FORBIDDEN with the message:
You do not have permission to request this resource (CatalogResource) using GET
method..
This is custom documentation. For more information, please visit the SAP Help Portal
127
5/27/2022
restjersey.security.de.hybris.platform.restjersey.resources=
restjersey.security.de.hybris.platform.restjersey.resources.CatalogsResource=
restjersey.security.de.hybris.platform.restjersey.resources.CatalogResource=
admingroup[GET,PUT,DELETE,POST]
or
restjersey.security.de.hybris.platform.restjersey.resources.CatalogResource=
admingroup[GET,PUT,DELETE,POST]
Request
Response
http://localhost:9001/ws410/rest/catalogs/
HTTP status FORBIDDEN with the message:
The (CatalogsResource) resource is not available for any user.
http://localhost:9001/ws410/rest/catalogs/hwcatalog/
Retrieve the speci ed catalog.
restjersey.security.de.hybris.platform.restjersey.resources=
restjersey.security.de.hybris.platform.restjersey.resources.CatalogsResource=
restjersey.security.de.hybris.platform.restjersey.resources.CatalogResource=
or any properties.
Request
Response
http://localhost:9001/ws410/rest/catalogs/
HTTP status FORBIDDEN with the message:
The (CatalogsResource) resource is not available for any user.
http://localhost:9001/ws410/rest/catalogs/hwcatalog/
HTTP status FORBIDDEN with the message:
The (CatalogsResource) resource is not available for any user.
Custom Security Strategy
It is possible for users to create their own security strategies by:
Implementing the SecurityStrategy interface:
public interface SecurityStrategy
{
boolean isResourceOperationAllowed(final RestResource resource, final String operation);
boolean isResourceCommandAllowed(final RestResource resource, final String command);
boolean isDtoOperationAllowed(final Class<?> objectClass, final String operation);
boolean isAttributeOperationAllowed(final Class<?> attrObjectClass, final String attrQualifier, final String attrOperation);
}
Registering the bean in platformwebservices-web-spring.xml:
platformwebservices-web-spring.xml
<beans>
<!-- ... --->
<bean id="securityStrategy" class="de.hybris.platform.webservices.CustomSecurityStrategy" scope="prototype" parent="abstractSecurit
<!-- ... --->
</beans>
Security Speci c Web Services Resources
Security Speci c Web Services Resources
Checking Credentials:
A request for a validation of the provided credentials:
http://localhost:9001/ws410/rest/login
If the login process is:
Valid: Status is 200 OK
Invalid: Status is 401 Unauthorized
Lost Password Scenario
This is custom documentation. For more information, please visit the SAP Help Portal
128
5/27/2022
If the restjersey.security property is set to enabled, only RetrievePasswordResource is available for users who lost their passwords.
They have to access to http://localhost:9001/ws410/rest/retrievepassword resource without using basic authentication.
For example, editor user forgets his password. He uses GET method and the following URL path:
http://localhost:9001/ws410/rest/retrievepassword/editor. If the user does not have access to PasswordQuestion and AnswerQuestion it is not possible to
retrieve password. In other cases, user can retrieve password.
The GET method returns response with PasswordQuestion.
Now, user uses PUT method and the same URL path:
http://localhost:9001/ws410/rest/retrievepassword/editor
He places PasswordAnswer within body request and executes request.
<user uid="http://localhost:9001/ws410/rest/retrievepassword/editor">
<passwordAnswer>YOUR ANSWER</passwordAnswer>
</user>
If the PasswordAnswer is correct, user retrieves a new password in raw format. In database the password is encoded into a md5 hash.
Change Password Scenario
Use http://localhost:9001/ws410/rest/changepassword, PUT method and the following HTTP body:
<changepassword>
<newpassword>NO EMPTY</newpassword>
</changepassword>
If you log in correctly, the new password is set.
Security Architecture Con guration
Con guring the WebServices API security architecture is done by editing two XML le located in the platformwebservices extension.
The following two les determine the security architecture con guration for the WebServices API security architecture:
web.xml
platformwebservices-web-spring.xml
The rst allows you to hook the font end into Spring Security. The second is the Spring con guration le.
Web.xml Con guration
This web.xml le is a hook into the Spring Security web infrastructure. DelegatingFilterProxy is a Spring Framework class that delegates to a lter implementation
which is de ned as a Spring bean in your application context. In this example, the bean is named springSecurityFilterChain, which is an internal infrastructure bean
created by the namespace to handle web security. Note that you should not use this bean name yourself.
<web-app>
<!-- ... -->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- ... -->
</web-app>
Once you have de ned the lter and mapping in web.xml, the next step is con guring the Spring application context le.
Spring Con guration
Con gure web security services in your Spring application context using security elements. The following is an example platformwebservices-web-spring.xml le.
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
This is custom documentation. For more information, please visit the SAP Help Portal
129
5/27/2022
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.0.xsd
http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd">
<!-- ... -->
<security:http>
<security:intercept-url pattern="/**" />
<security:http-basic />
<security:logout />
<security:remember-me />
</security:http>
<security:authentication-manager alias="mainAuthenticationManager">
<security:authentication-provider user-service-ref="userDetailsService">
<security:password-encoder ref="hybrisPasswordValidator">
<!-- SaltedMD5PasswordEncoder is used -->
<!-- <security:salt-source user-property="whatever"/> -->
</security:password-encoder>
</security:authentication-provider>
</security:authentication-manager>
<bean id="userDetailsService"
class="de.hybris.platform.webservices.security.impl.HybrisUserDetailsService"
scope="prototype">
<property name="userService" ref="userService"/>
<property name="modelService" ref="modelService"/>
<property name="encryptionInfo" ref="encryptionInfo"/>
</bean>
<bean id="hybrisPasswordValidator"
class="de.hybris.platform.webservices.security.impl.HybrisPasswordValidator">
<property name="encryptionInfo" ref="encryptionInfo"/>
</bean>
<bean id="encryptionInfo"
class="de.hybris.platform.webservices.security.impl.EncryptionInfo"/>
<!-- ... -->
</beans>
Key aspects of this con guration include the following:
http con guration
This element enables web security, and denotes that all URLs within our web services should be secured. The WebService API uses basic authentication which prompts the
user for a login when they attempt to access a protected resource.
authentication-provider and password-encoder
The SAP Commerce web services framework authenticates users against HMC members. The SAP Commerce implementation of the Spring Security
UserDetailsService, handles the password validation procedure. Some users have encrypted passwords and others do not. The hybrisPasswordValidator class
takes appropriate care of password comparison.
Related Information
HMC Access Rights
Web Service API - Session Language
The SAP Commerce Web Service API offers you the possibility to specify the session language to be used. This is achieved by using the HTTP Accept-Language Header, and
maps the provided isocode to the session language of the SAP Commerce session.
Setting the Accept-Language Header
When using the SAP Commerce Web Service API, the active session language can be set by adding an Accept-Language header. This can contain a single language isocode or
a comma separated list of isocodes.
If more than one isocode is speci ed, the isocodes are processed as described by W3C de nition. If the requested isocode is not available, the next speci ed isocode from the
list is used. If no isocode is speci ed or none of the speci ed languages is available, no session language is set. Each language may be given an associated quality value which
represents an estimate of the user's preference for that language. The quality value defaults to q=1. For example, the following setting means that Danish language is
prefered, but German and English are also accepted:
Accept-Language: da, de;q=0.8, en;q=0.7
RESTClient Example
Sending HTTP request with Accept-Language header set to the value en;q=0.4, de;q=0.6.
This is custom documentation. For more information, please visit the SAP Help Portal
130
5/27/2022
cURL Example
curl -u admin:nimda -H "Accept-Language: de;q=0.4, en;q=0.6" http://localhost:9001/ws410/rest/catalogs
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<catalogs uri="http://localhost:9001/ws410/rest/catalogs">
<catalog id="Default" pk="8796093055576" uri="http://localhost:9001/ws410/rest/catalogs/Default"/>
<catalog id="hwcatalog" pk="8796093088344" uri="http://localhost:9001/ws410/rest/catalogs/hwcatalog"/>
<catalog id="clothescatalog" pk="8796093121112" uri="http://localhost:9001/ws410/rest/catalogs/clothescatalog"/>
<catalog id="SampleClassification" pk="8796093153880"
uri="http://localhost:9001/ws410/rest/classificationsystems/SampleClassification"/>
</catalogs>
WebService DTO Concept
Data Transfer Objects (DTOs) are a key part of the SAP Commerce WebService framework. They serve as intermediary objects between the models in the ServiceLayer, and
a web service client.
DTOs are Plain Old Java Objects (POJOs) that are annotated with:
JAXB annotations describing how they can be marshalled or unmarshalled into XML
GraphNode and GraphProperty, which are SAP Commerce speci c annotations that inform the SAP Commerce GraphTransformer how to map a DTO to and from a
model in the ServiceLayer
An illustration of the context in which the DTO is used.
The DTO Generation Process
While each DTO is a simple POJO, there are certain features they posses:
DTOs may implement the Modi edProperties interface in order to keep track of which properties have been changed:
public class ProductFeatureDTO implements ModifiedProperties
{
protected final Set<String> modifiedPropsSet = new HashSet<String>();
..........
}
DTOs can contain plain properties as well as complex ones, also other DTOs
This is custom documentation. For more information, please visit the SAP Help Portal
131
5/27/2022
DTO property names are equal to property names of the respective model class and are case sensitive:
private String qualifier;
private String name;
private String code;
private String value;
private String unit;
DTO properties should not be initialized with default values
Each DTO property should be represented by a model property. The only exception is uri, because it does not exist in the model, but is the necessary DTO parameter
for web services.
It is not necessary that each model property is represented by a DTO property.
The JAXB-annotations @XmlRootElement and @XmlAttribute describe how the DTO can be marshalled or unmarshalled into XML:
@XmlRootElement(name = "classificationvalue")
public class ProductFeatureDTO implements ModifiedProperties
{
...........................
@XmlAttribute
public String getQualifier()
{
return qualifier;
}
@XmlAttribute
public String getName()
{
return name;
}
}
The GraphNode and GraphProperty annotations instruct the GraphTransformer how to transform the DTO to and from the model.
@GraphNode(target = ProductFeatureModel.class, factory = GenericNodeFactory.class, uidProperties = "qualifier")
.......................................
@GraphProperty(virtual = true, interceptor = ProductFeatureConverter.class)
public void setName(final String name)
{
this.modifiedPropsSet.add("name");
this.name = name;
}
@GraphProperty(interceptor = ClassificationAttributeValueModelToStringConverter.class)
public void setValue(final String value)
{
this.modifiedPropsSet.add("value");
this.value = value;
}
Customizing DTOs
Two default DTO implementations are generated for each model in the ServiceLayer, as well as two resource les, and a spring context le. These DTOs contain the required
JAXB and GraphNode annotations to support default transformation between a DTO and a model. However, you may need to specify custom behavior when mapping
between a DTO and a model. This may be the case in the following examples:
There is special or unusual JAXB marshalling required for a DTO attribute
Some virtual DTO attributes are needed, which do not map one-to-one to attributes in the model, but perhaps represent an amalgamation of a number of model
attributes
You would like to specify particular conversions to take place, for example from a String to Enum eld
In order to customize the behavior of a DTO, you should do the following:
1. Create a copy of the default DTO implementation and customize it appropriately
2. Create the following directories: extension /custom/src
3. Place it in the correct package path:
.../customdto/... instead of .../dto/...
4. Call ant
To know what options are available for DTO customization, it is necessary to understand the meanings of the various annotations.
JAXB-Annotations
JAXB annotations used in the DTOs include the following:
JAXB annotation
Description
@XmlRootElement
Maps a class or an Enum type to an XML element.
@XmlElement
Maps a JavaBean property to a XML element derived from property name. A JavaBean
property, when annotated with @XmlElement annotation is mapped to a local element in the
XML schema complex type, to which the containing class is mapped.
This is custom documentation. For more information, please visit the SAP Help Portal
132
5/27/2022
JAXB annotation
Description
@XmlElementWrapper
Generates a wrapper element around XML representation. This is primarily intended to be
used to produce a wrapper XML element around collections. The annotation therefore
supports two forms of serialization shown below, which allows a null collection to be
represented either by the absence or presence of an element with a nullable attribute.
//Example: code fragment
int[] names;
// XML Serialization Form 1 (Unwrapped collection)
<names> ... </names>
<names> ... </names>
// XML Serialization Form 2 ( Wrapped collection )
<wrapperElement>
<names> value-of-item </names>
<names> value-of-item </names>
....
</wrapperElement>
The @XmlElementWrapper annotation can be used with the following elements:
JavaBean properties
Non-static, non-transient elds
SAP Commerce GraphTransformer Annotations
The GraphTransformer annotations: GraphNode and GraphProperty determine how the GraphTransformer should map a DTO to and from a model:
GraphNode
The GraphNode has a number of attributes:
Attribute
Description
target
Speci es the model class, with which this DTO is paired
@GraphNode(target = ProductFeatureModel.class ....)
public class ProductFeatureDTO
factory
A Factory nder to determine which target model class to pair to. If this factory returns null, the target class is used.
addNodes
A list of dependent sub-object nodes to be added to the Graph. These are normally detected automatically, unless the
nodes are elements of collections.
@GraphNode(target = PaymentInfoModel.class, uidProperties = "code", addNodes =
{ CreditCardPaymentInfoDTO.class, DebitPaymentInfoDTO.class, AdvancePaymentInfoDTO.class,
InvoicePaymentInfoDTO.class })
public class PaymentInfoDTO implements ModifiedProperties
{
...
uidProperties
A comma separated literals de ning the identi ers used to uniquely identify this object. If no value is provided its hash
code is used instead.
@GraphNode(target = ProductFeatureModel.class, factory = GenericNodeFactory.class,
uidProperties = "qualifier")
@XmlRootElement(name = "classificationvalue")
public class ProductFeatureDTO implements ModifiedProperties
{
GraphProperty
The GraphProperty provides property speci c con guration:
Attribute
Description
interceptor
Class of interceptor, which may do some conversion or act as factory
This is custom documentation. For more information, please visit the SAP Help Portal
133
5/27/2022
Attribute
Description
typecheck
A boolean value used when an interceptor is de ned, to guide how source and target
properties are to be converted between each other:
If true (strict), the property is only accepted when target type is assignable from
source type. Examples of strict type checking are:
String -> String: pass
Integer -> Number: pass
Number -> Integer: do not pass
Integer -> Double: not accepted
If false (weak), the property is accepted when target type is assignable from source
type or source type is assignable from target type. Examples of weak type checking
are:
String -> String: pass
Integer -> Number: pass
Number -> Integer: pass
Integer -> Double: not accepted
virtual
A virtual property is one that exists in the DTO, but not in the model. For details see
Implementing a Virtual Attribute
Implementing a Virtual Attribute
As mentioned above, a virtual attribute does not exist in models. An example could be price, which is available in the target object but not in the source object, or composed
properties which are calculated based on other various properties. The other example is uri attribute, which also does not exit in a model and is required for web services. In
SAP Commerce it is de ned in the AbstractItemDTO as a virtual property.
If an additional interceptor is assigned, the virtual property can be calculated during graph processing.
Here is an example for getting and setting a virtual attribute with some custom logic:
@XmlAttribute
@GraphProperty(virtual = true)
public String getVirt(){
return virt == null ? "virtual value" : virt;
}
@GraphProperty(virtual = true, interceptor = VirtInterceptor.class)
public void setVirt(final String name){
this.virt = name;
}
public class VirtInterceptor implements PropertyInterceptor<Object, String>{
@Override
public String intercept(final PropertyContext propertyCtx, final Object propertyValue){
// Custom code for calculating the value of the virtual property
return ...
}
Implementing a Virtual DTO
To create a DTO that does not correspond to any type system, you should create a POJO DTO. For example, let us consider a web service call that returns a summary of the
basic health and status of the system including:
The number of users
The number of sessions
The number of products
Some JVM memory and processor statistics including: Runtime.totalMemory, Runtime.freeMemory, Runtime.availableProcessors
It can be implemented by creating a DTO and Resource that is not related to any SAP Commerce model, but instead contains only the required information. The code
samples below illustrate the example.
DiagnosticDTO.java
public interface DiagnosticDTO
{
Integer getUsersCount();
Integer getSessionsCount();
Integer getProductsCount();
This is custom documentation. For more information, please visit the SAP Help Portal
134
5/27/2022
String getMemoryInfo();
}
DiagnosticDTOImpl.java
@XmlRootElement(name = "diagnostic")
public class DiagnosticDTOImpl implements DiagnosticDTO
{
/*
* (non-Javadoc)
*
* @see de.hybris.platform.aspecttest.dto.DiagnosticDTO#getMemoryInfo()
*/
@XmlElement
@Override
public String getMemoryInfo()
{
return String.format("JVM Memory Info, total:%sMB , free:%sMB , processors count:%s",//
Long.valueOf(Runtime.getRuntime().maxMemory() / (1024 * 1024)),//
Long.valueOf(Runtime.getRuntime().freeMemory() / (1024 * 1024)),//
Long.valueOf(Runtime.getRuntime().availableProcessors()));
}
public void setMemoryInfo(final String info)
{
//
}
/*
* (non-Javadoc)
*
* @see de.hybris.platform.aspecttest.dto.DiagnosticDTO#getProductsCount()
*/
@XmlAttribute
@Override
public Integer getProductsCount()
{
// YTODO Auto-generated method stub
final FlexibleSearchQuery query = new FlexibleSearchQuery("select {PK} from {Product}");
final FlexibleSearchService service = Registry.getApplicationContext().
getBean(FlexibleSearchService.class);
JaloSession.getCurrentSession().getSessionContext()
.setAttribute(FlexibleSearch.DISABLE_RESTRICTIONS, Boolean.TRUE);
final SearchResult result = service.search(query);
return Integer.valueOf(result.getTotalCount());
}
public void setProductsCount(final Integer count)
{
//
}
/*
* (non-Javadoc)
*
* @see de.hybris.platform.aspecttest.dto.DiagnosticDTO#getSessionsCount()
*/
@XmlAttribute
@Override
public Integer getSessionsCount()
{
return Integer.valueOf(JaloConnection.getInstance().getAllSessions().size());
}
public void setSessionsCount(final Integer count)
{
//
}
/*
* (non-Javadoc)
*
* @see de.hybris.platform.aspecttest.dto.DiagnosticDTO#getUsersCount()
*/
@XmlAttribute
@Override
public Integer getUsersCount()
{
final SearchResult result = Registry.getApplicationContext().getBean(FlexibleSearchService.class)
.search("select {PK} from {User}");
return Integer.valueOf(result.getTotalCount());
}
public void setUsersCount(final Integer count)
{
//
}
}
 Note
Annotations
This is custom documentation. For more information, please visit the SAP Help Portal
135
5/27/2022
Remember to add only @XmlElement and @XmlAttribute annotation for one attribute. Providing a separate annotation for getter and setter results in an exception.
If you want to use a custom virtual DTO in your code, you should override and extend the platformNotFromSystemDtosClasses bean de nition:
<bean id="platformNotFromSystemDtosClasses"
class="org.springframework.beans.factory.config.ListFactoryBean">
<property name="sourceList">
<list>
<value type="java.lang.Class">com.sun.research.ws.wadl.Application</value>
<value type="java.lang.Class">de.hybris.platform.webservices.dto.AbstractItemDTO
</value>
<value type="java.lang.Class">de.hybris.platform.webservices.dto.AbstractCollectionDTO
</value>
<value type="java.lang.Class">de.hybris.platform.webservices.dto.credentials.PasswordDTO
</value>
<value type="java.lang.Class">de.hybris.platform.webservices.dto.price.PriceDTO
</value>
<value type="java.lang.Class">de.hybris.platform.webservices.dto.VariantAttributeDTO
</value>
<value type="java.lang.Class">de.hybris.platform.webservices.dto.CustomTypesDTO
</value>
....
<value type="java.lang.Class">de.hybris.platform.aspecttest.dto.impl.DiagnosticDTOImpl
</value>
</list>
</property>
</bean>
Related Information
Customizing Resources and DTOs
WebService Resource Concept
Resources are an essential part of the WebService framework, allowing secure CRUD access to models in the ServiceLayer.
The Resource Generation Process
Data models can change frequently, and you should ensure that resources and corresponding items and models are synchronized with each other. As the contents of
resources can be extrapolated from the model and JAX-RS conventions, it is possible to automatically generate default resources and DTOs in the build process. In particular,
for each type that is not de ned as abstract in items.xml le and has a generateModel ag set to true, two les are created:
For a single resource: representing individual instances of the model
For collection of resources: representing collections of that model
This not only ensures that resources stay in synchronization with the model de nitions, but also saves the developer having to write standard plumbing code. Parts of
generated les for resource are given below for illustration:
Collections of Resources
The automatically generated le for a collection of resources contains the following methods:
Getter method for accessing all instances of this type
Getter method for accessing an abbreviated description of a single instance in this collection
@Path("{cart}")
public AbstractResource getCartResource(@PathParam("cart") final String resourceKey)
{
final CartResource resource = resourceCtx.getResource(CartResource.class);
resource.setResourceId(resourceKey );
resource.setParentResource(this);
return resource;
}
The unique identi er passed to the latter is determined in items.xml by the unique eld of the attribute element and if none exists the pk is used.
Single Resources
A single resource is used to access more details of a speci c model and to allow CRUD operations on it. Features include:
HTTP methods covering DELETE, GET and PUT operations:
@DELETE
public Response deleteLanguage()
{
return createDeleteResponse().build();
}
@GET
public Response getLanguage()
{
return createGetResponse().build();
}
This is custom documentation. For more information, please visit the SAP Help Portal
136
5/27/2022
@PUT
public Response putLanguage(final LanguageDTO dto)
{
return createPutResponse(dto).build();
}
Getter and setter methods for the underlying model, which are used to get and set references to the model between various resources:
public LanguageModel getLanguageModel()
{
return super.getResourceValue();
}
public void setLanguageModel(final LanguageModel value)
{
super.setResourceValue(value);
}
A @Path-annotated method for accessing sub-resources of the collection:
@Path("/countries/{country}")
public AbstractResource getCountryResource(@PathParam("country") final String resourceKey)
{
final CountryResource resource = resourceCtx.getResource(CountryResource.class);
resource.setResourceId(resourceKey );
resource.setParentResource(this);
return resource;
}
The readResource method for fetching data of an instance in the collection.
If the speci ed type has no unique identi er, the pk is used for resourceId:
@Override
protected OrderEntryModel readResource(final String resourceId) throws Exception
{
return serviceLocator.getModelService().get(PK.parse(resourceId));
}
If the unique identi er is speci ed and is of type java.lang.String, as is the case for LanguageModel where it is isoCode, the generated method is:
@Override
protected LanguageModel readResource(final String resourceId) throws Exception
{
LanguageModel model = new LanguageModel();
model.setIsocode(resourceId);
return serviceLocator.getModelService().getByExample(model);
}
Customizing Resources
You may wish to extend the default resource implementation to add custom behavior in the following situations:
When custom logic should be performed before or after a model is updated. For example when a cart model is updated we would like to recalculate the value of its
contents.
Special handling of the URI path is required, such that the context, in which the current resource has been identi ed is extracted from the URI path
Below two ways of resource customizing is presented: the rst does not require creating a custom resource, and the second one does. That is followed by a third option for
creating virtual resources.
Customizing Without Needing a New Resource
1. Create a class that extends one of the following:
HttpGetResponseBuilder for handling speci c behavior of GET request
HttpDeleteResponseBuilder for handling speci c behavior of DELETE request
HttpPostResponseBuilder for handling speci c behavior of POST request
HttpPutResponseBuilder for handling speci c behavior of PUT request
For example:
public class PutCartEntryMethod extends HttpPutResponseBuilder<CartEntryModel, CartEntryDTO>
{
@Override
public void afterProcessing(final CartEntryDTO dto, final CartEntryModel resource, final boolean wasCreated)
{
final CartModel order = resource.getOrder();
if (resource.getQuantity().longValue() <= 0)
{
getResource().getServiceLocator().getModelService().remove(resource);
}
// recalculates cart
getResource().getServiceLocator().getCartService().calculateCart(order);
}
}
2. Wire it to the resource being customized by adding the correct property to the bean:
This is custom documentation. For more information, please visit the SAP Help Portal
137
5/27/2022
<bean id="cartEntryResource" class="de.hybris.platform.core.resource.order.CartEntryResource"
scope="prototype" parent="abstractResource">
<property name="putMethod"
value="de.hybris.platform.webservices.resources.methods.cartentry.PutCartEntryMethod" />
</bean
This gives an opportunity to extend the default behavior without changing anything in the generated resources.
Customizing By Adding a Custom Resource
1. Implement a custom resource or DTO
2. Create the following directories: extension /custom/src
3. Put the custom implementation into the proper package path:
.../customresource/... instead of .../resource/... for custom resources
.../customdto/... instead of .../dto/... for custom DTOs
4. Call ant
By placing the custom resource in the customresource folder, it is seen and executed instead of the default one.
 Note
Note that resources in the resource folder are overwritten during the build process, so you should always place your custom resources in the customresource folder.
Any custom logic required before performing CRUD methods or right after them, can be de ned in the custom resource le in two ways:
By providing custom methods as described earlier: HttpGetResponseBuilder, PostResponseBuilder, PutResponseBuilder, DeleteResponseBuilder
By implementing any of the methods below:
Method
Purpose
afterDelete
For logic that is performed after deleting a resource
afterPut
For logic that is performed after putting a resource
afterPost
For logic that is performed after posting a resource
beforeDelete
For logic is be performed before deleting a resource
beforePut
For logic that is performed before putting a resource
beforePost
For logic that is performed before posting a resource
Custom Resource Reference
When a resource is required for an item that do not actually exist, it is possible to de ne a custom resource, though not in
extension name /custom/src as no DTO or resource is generated for it.
1. De ne the resource:
public class PriceResource extends AbstractResource<PriceDTO>
...
2. Implement at least the readResource method:
@Override
protected PriceDTO readResource(final String resourceId) throws Exception
{
final ProductModel model = (ProductModel) getParentResource().getResourceValue();
final ServiceLocator service = getParentResource().getServiceLocator();
....
}
3. Add CRUD entry points, for example GET:
@GET
@Consumes(MediaType.APPLICATION_XML)
public Response getPrice(){
final PriceDTO price = getResourceValue();
getResponse().entity(price);
return getResponse().build();
}
Use it within other custom resource:
public class ProductResource extends AbstractYResource<ProductModel>{
....
@Path("defaultprice")
public AbstractResource getDefaultPrice()
{
final ProductModel product = this.getResourceValue();
AbstractResource result = this;
This is custom documentation. For more information, please visit the SAP Help Portal
138
5/27/2022
if (product != null)
{
result = resourceCtx.getResource(PriceResource.class);
result.setParentResource(this);
((PriceResource) result).setPricingStrategy(((PriceResource) result).new DefaultPricingStrategy());
}
return result;
}
Note that this resource is available for a single ProductResource with /defaultprice suffix at the end of URL.
Implementing Virtual Resource
DiagnosticResource.java
@Path("/diagnostic")
@SuppressWarnings("PMD")
public class DiagnosticResource extends AbstractCollectionResource
{
/**
* @param composedTypeName
*/
public DiagnosticResource(final String composedTypeName)
{
super(composedTypeName);
// YTODO Auto-generated constructor stub
}
public DiagnosticResource()
{
super("diagnostic");
// YTODO Auto-generated constructor stub
}
@GET
public Response getDiagnosticData()
{
final DiagnosticDTO ci = new DiagnosticDTOImpl();
getResponse().entity(ci);
return getResponse().build();
}
}
Related Information
Key Features and Implementation Details
Customizing Resources and DTOs
Web Services in Action
This section presents Commerce Platform Web Services in action, and includes examples of API usage, REST commands, Web Services clients, and customization examples.
The two principle topics are:
Web Services Clients: Common web service clients that may be used by the SAP Commerce WebService API
Web Services Examples: Examples of REST dialogs between a client and a web server
Web Services Clients
Different clients may be used with the platformwebservices extension, providing some exibility in developing and using your custom services. Clients that we have tested
are outlined here, with links to further information on each.
SAP Commerce experience using the following clients:
cURL Command Line Tool: Command line tool for transferring data with URL syntax.
RESTClient
: A Java application to assist in testing and debugging RESTful web services
The Jersey Test Framework
a basis for our own web service unit tests
cURL Command Line Tool
cURL is a command line tool for transferring data with URL syntax, and supporting different network protocols. cURL can be used as a client with Commerce Platform web
services.
Command Syntax
In order to use cURL, you should type curl at the command line followed by any additional options and the URL of the output you wish to retrieve or post as follows:
curl <options> <url>
This is custom documentation. For more information, please visit the SAP Help Portal
139
5/27/2022
Options
The following options may be applied in cURL in order to use SAP Commerce functionality via the SAP Commerce platformwebservices extension:
Command
Description
-u user:password
Speci es the user name and password to use for server authentication.
-X command
Speci es a custom request method to use when communicating with the HTTP server. For
details see the HTTP Methods section below.
-d @ lename
Sends the data contained a speci ed le to the HTTP server. @ followed be a le name
speci es the le to read the data from.
-H header
Extra header to use when getting a web page.
HTTP Methods
There are ve different HTTP methods available that may be used by cURL.
GET
The GET method requests to retrieve a content of a resource speci ed in the URL request.
curl -u user:password uri/resources
PUT
The PUT method requests to store a content of a speci ed le in the location indicated in URL. There are two options possible:
Creates a new resource if you send the full content of the speci ed resource,
Updates a resource if you update the full content of the speci ed resource.
curl -u user:password -X PUT -d @file.xml -H "Content-type: application/xml" uri/resource
POST
The POST method requests to store a content of a speci ed le in the location indicated in URL. There are two options possible:
Create a subordinate of the speci ed resource,
Update a resource if you request the server to update one or more subordinates of the speci ed resource.
On the contrary to PUT method, you do not need to send the full content of the speci ed resource.
curl -u user:password -X POST -d @file.xml -H "Content-type: application/xml" uri/resources
DELETE
The DELETE method requests that the HTTP server removes a resource speci ed by URL.
curl -u user:password -X DELETE uri/resource
OPTIONS
The OPTIONS method requests for information about the communication options available on the request-response chain speci ed by the URL.
curl -u user:password -X OPTIONS uri/resources
Examples of Usage
GET
The following example presents how to retrieve a list of all countries and print the results in the standard output:
This is custom documentation. For more information, please visit the SAP Help Portal
140
5/27/2022
curl -u admin:nimda http://localhost:9001/ws410/rest/countries
It is possible to save the output in a le, for example countries.xml:
curl -u admin:nimda http://localhost:9001/ws410/rest/countries > countries.xml
The result of the above request is:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<countries>
<country uri="http://localhost:9001/ws410/rest/countries/ch"
<country uri="http://localhost:9001/ws410/rest/countries/de"
<country uri="http://localhost:9001/ws410/rest/countries/se"
<country uri="http://localhost:9001/ws410/rest/countries/pl"
<country uri="http://localhost:9001/ws410/rest/countries/uk"
<country uri="http://localhost:9001/ws410/rest/countries/at"
<country uri="http://localhost:9001/ws410/rest/countries/us"
<country uri="http://localhost:9001/ws410/rest/countries/nl"
</countries>
isocode="ch"/>
isocode="de"/>
isocode="se"/>
isocode="pl"/>
isocode="uk"/>
isocode="at"/>
isocode="us"/>
isocode="nl"/>
cURL can also retrieve a speci ed range of information. For details see WebService API - Extended Collection.
curl -u admin:nimda "uri/resources/?resources_page=page_number&resources_size=resource_count&resources_sort=attribute"
where:
resources_page - page number, beginning from 0,
resources_size - page size,
resources_sort - attribute for sorting.
 Note
If the URL contains the & char, it must be written in quotes.
The below example presents 10 positions from the rst page of customers resource sorted by uid:
curl -u admin:nimda "http://localhost:9001/ws410/rest/customers/?customers_page=0&customers_size=10&customers_sort=uid"
DELETE
In the example below, pl is removed from countries resource:
curl -u admin:nimda -X DELETE http://localhost:9001/ws410/rest/countries/pl
The result after perfoming the above request is:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<countries>
<country uri="http://localhost:9001/ws410/rest/countries/ch"
<country uri="http://localhost:9001/ws410/rest/countries/de"
<country uri="http://localhost:9001/ws410/rest/countries/se"
<country uri="http://localhost:9001/ws410/rest/countries/uk"
<country uri="http://localhost:9001/ws410/rest/countries/at"
<country uri="http://localhost:9001/ws410/rest/countries/us"
<country uri="http://localhost:9001/ws410/rest/countries/nl"
</countries>
isocode="ch"/>
isocode="de"/>
isocode="se"/>
isocode="uk"/>
isocode="at"/>
isocode="us"/>
isocode="nl"/>
PUT
In the example below, a new country resource is created and stored on the server.
curl -u admin:nimda -X PUT -d @PUT.xml -H "Content-type: application/xml" http://localhost:9001/ws410/rest/countries/pl
PUT.xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<country isocode="pl">
<active>true</active>
<name>Poland</name>
</country>
The result after performing the above request is:
This is custom documentation. For more information, please visit the SAP Help Portal
141
5/27/2022
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<countries>
<country uri="http://localhost:9001/ws410/rest/countries/ch"
<country uri="http://localhost:9001/ws410/rest/countries/de"
<country uri="http://localhost:9001/ws410/rest/countries/se"
<country uri="http://localhost:9001/ws410/rest/countries/uk"
<country uri="http://localhost:9001/ws410/rest/countries/at"
<country uri="http://localhost:9001/ws410/rest/countries/us"
<country uri="http://localhost:9001/ws410/rest/countries/nl"
<country uri="http://localhost:9001/ws410/rest/countries/pl"
</countries>
isocode="ch"/>
isocode="de"/>
isocode="se"/>
isocode="uk"/>
isocode="at"/>
isocode="us"/>
isocode="nl"/>
isocode="pl"/>
POST
The example below presents how to extend the existing companies resource by appending another company.
The companies resource at the beginning contains one company:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<companies>
<company uid="hybris">
<locname>hybris GmbH</locname>
<addresses uri="http://localhost:9001/ws410/rest/addresses/8796093054999" pk="8796093054999"/>
<buyer>true</buyer>
<manufacturer>false</manufacturer>
<vatID>DE 200689264</vatID>
</company>
<company uid="testfirma">
<locname>Test company</locname>
<buyer>false</buyer>
<manufacturer>false</manufacturer>
</company>
</companies>
After applying the method below:
curl -u admin:nimda -X POST -d @POST.xml -H "Content-type: application/xml" http://localhost:9001/ws410/rest/companies
POST.xml
<company uid="NewCo">
<locname>New company</locname>
<buyer>false</buyer>
<manufacturer>false</manufacturer>
</company>
The resulting companies resource is:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<companies>
<company uid="hybris">
<locname>hybris GmbH</locname>
<addresses uri="http://localhost:9001/ws410/rest/addresses/8796093054999" pk="8796093054999"/>
<buyer>true</buyer>
<manufacturer>false</manufacturer>
<vatID>DE 200689264</vatID>
</company>
<company uid="NewCo">
<locname>New company</locname>
<buyer>false</buyer>
<manufacturer>false</manufacturer>
</company>
<company uid="testfirma">
<locname>Test company</locname>
<buyer>false</buyer>
<manufacturer>false</manufacturer>
</company>
</companies>
OPTIONS
The example displays all HTTP methods available for countries resource:
curl -u admin:nimda -X OPTIONS http://localhost:9001/ws410/rest/countries
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<application xmlns="http://research.sun.com/wadl/2006/10">
<doc xmlns:jersey="http://jersey.dev.java.net/" jersey:generatedBy="Jersey: 1.0.3.1 08/14/2009 04:19 PM"/>
<resources base="http://localhost:9001/ws410/rest/">
<resource path="countries">
<method name="GET" id="getCountries">
<response>
<representation mediaType="application/xml"/>
This is custom documentation. For more information, please visit the SAP Help Portal
142
5/27/2022
<representation mediaType="application/json"/>
</response>
</method>
<resource path="{isoCode}">
<param xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:string"
style="template" name="isoCode"/>
<method name="GET" id="getCountry">
<response>
<representation mediaType="application/xml"/>
<representation mediaType="application/json"/>
</response>
</method>
<method name="DELETE" id="deleteCountry">
<response>
<representation mediaType="application/xml"/>
<representation mediaType="application/json"/>
</response>
</method>
<method name="PUT" id="putCountry">
<request>
<representation mediaType="*/*"/>
</request>
<response>
<representation mediaType="application/xml"/>
<representation mediaType="application/json"/>
</response>
</method>
<resource path="regions"/>
</resource>
</resource>
</resources>
</application>
Using cURL for CronJobs
Creating CronJobs
The POST method can be used to create a new CronJob:
curl -u user:password -X POST -d @file.xml -H "Content-type: application/xml" uri/cronjobs/code?cmd=CreateCronJobCommand
Example:
curl -u admin:nimda -X POST -d @POST_CJ.xml -H "Content-type: application/xml" http://localhost:9001/ws410/rest/cronjobs/0000000F?cmd=
POST_CJ.xml
<cronjob code="0000001F" >
</cronjob>
 Note
The CronJob code in xml le should be unique and can not already exist, whereas the CronJob code given in URL represents the base CronJob.
Starting CronJobs
The PUT method can be used to start a CronJob:
curl -u user:password -X PUT -d @file.xml -H "Content-type: application/xml" "uri/cronjobs/code?cmd=StartCronJobCommand&synchronous=tr
Example:
curl -u admin:nimda -X PUT -d @PUT_CJ.xml -H "Content-type: application/xml" "http://localhost:9001/ws410/rest/cronjobs/0000001F?cmd=S
PUT_CJ.xml
<cronjob code="0000001F" >
</cronjob>
 Note
The CronJob code must be the same in URL and in xml le.
Related Information
http://curl.haxx.se/docs/manpage.html
This is custom documentation. For more information, please visit the SAP Help Portal
143
5/27/2022
Web Services Examples
The SAP Commerce WebService API supports the following CRUD operations: GET, PUT, POST, and DELETE. This topic contains examples of CRUD operations, including
both single resource and collection calls for country resources.
Get All Countries
Method
GET
URL
http://localhost:9001/ws410/rest/countries
Body
-
Response Body
<?xml version="1.0" encoding="UTF-8"?>
<countries>
<country isocode="de" uri="http://localhost:9001/ws410/rest/countries/de"/>
<country isocode="at" uri="http://localhost:9001/ws410/rest/countries/at"/>
<country isocode="uk" uri="http://localhost:9001/ws410/rest/countries/uk"/>
<country isocode="ch" uri="http://localhost:9001/ws410/rest/countries/ch"/>
<country isocode="us" uri="http://localhost:9001/ws410/rest/countries/us"/>
<country isocode="pl" uri="http://localhost:9001/ws410/rest/countries/pl"/>
<country isocode="se" uri="http://localhost:9001/ws410/rest/countries/se"/>
<country isocode="nl" uri="http://localhost:9001/ws410/rest/countries/nl"/>
</countries>
HTTP Status Code
200 OK
More usage examples of CRUD operations for different resources are presented in API Usage Examples.
Limit the Number of Retrieved Results
Method
GET
URL
http://localhost:9001/ws410/rest/countries?
countries_size=5&countries_sort=isocode+asc
Body
-
Response Body
<?xml version="1.0" encoding="UTF-8"?>
<countries>
<country isocode="at" uri="http://localhost:9001/ws410/rest/countries/at"/>
<country isocode="ch" uri="http://localhost:9001/ws410/rest/countries/ch"/>
<country isocode="de" uri="http://localhost:9001/ws410/rest/countries/de"/>
<country isocode="nl" uri="http://localhost:9001/ws410/rest/countries/nl"/>
<country isocode="pl" uri="http://localhost:9001/ws410/rest/countries/pl"/>
</countries>
HTTP Status Code
200 OK
More usage examples of extended collection API usage for different resources are presented in Extended Collection API - Examples.
Get a Speci c Country
Method
GET
URL
http://localhost:9001/ws410/rest/countries/uk
Body
-
Response Body
<?xml version="1.0" encoding="UTF-8"?>
<country isocode="uk" pk="8796093120546" uri="http://localhost:9001/ws410/rest/countries/uk">
<creationtime>2010-05-04T15:19:48.227+02:00</creationtime>
<modifiedtime>2010-05-04T15:20:11.941+02:00</modifiedtime>
<active>true</active>
<name>United Kingdom</name>
<regions/>
<zones>
<zone code="europe" uri="http://localhost:9001/ws410/rest/zones/europe"/>
</zones>
</country>
HTTP Status Code
200 OK
This is custom documentation. For more information, please visit the SAP Help Portal
144
5/27/2022
Create a New Country
Method
PUT
URL
http://localhost:9001/ws410/rest/countries/it
Body
<?xml version="1.0" encoding="UTF-8"?>
<country isocode="it">
<active>true</active>
<name>Italy</name>
<regions/>
</country>
Response Body
-
HTTP Status Code
201 Created
Delete a Country
Method
DELETE
URL
http://localhost:9001/ws410/rest/countries/it
Body
-
Response Body
-
HTTP Status Code
200 OK
Related Information
cURL Command Line Tool
API Usage Examples
The WebService API supports common CRUD operations. The HTTP response contains a HTTP status code, and may also contain an additional entity body. The
application/xml and application/json MIME types are supported by all REST calls.
Users and User Resources
Return a Speci c User
Method
GET
URL
http://localhost:9001/ws410/rest/users/abrode
Body
-
Response Body
<?xml version="1.0" encoding="UTF-8"?>
<user uid="abrode">
<addresses>
<address uri="http://localhost:9001/ws410/rest/addresses/8796093382679"
pk="8796093382679"/>
</addresses>
<usergroups>
<usergroup uri="http://localhost:9001/ws410/rest/usergroups/customergroup"
uid="customergroup"/>
</usergroups>
<name>Arin Brode</name>
<sessionCurrency uri="http://localhost:9001/ws410/rest/currencies/EUR"
isocode="EUR"/>
<sessionLanguage uri="http://localhost:9001/ws410/rest/languages/de"
isocode="de"/>
</user>
HTTP Status Code
200 OK
Create a New User
Method
PUT
URL
http://localhost:9001/ws410/rest/users/hannes
This is custom documentation. For more information, please visit the SAP Help Portal
145
5/27/2022
Body
<?xml version="1.0" encoding="UTF-8"?>
<user uid="hannes">
<addresses>
<address pk="8796093382679"/>
</addresses>
<usergroups>
<usergroup uid="customergroup"/>
</usergroups>
<name>Hannes</name>
<sessionCurrency isocode="USD"/>
<sessionLanguage isocode="en"/>
</user>
Response Body
-
HTTP Status Code
201 Created
The uid must be a non existing value.
Delete a User
Method
DELETE
URL
http://localhost:9001/ws410/rest/users/hannes
Body
-
Response Body
-
HTTP Status Code
200 OK
Countries and Country Resources
Get All Countries
Method
GET
URL
http://localhost:9001/ws410/rest/countries
Body
-
Response Body
<?xml version="1.0" encoding="UTF-8"?>
<countries>
<country uri="http://localhost:9001/ws410/rest/countries/ch"
isocode="ch"/>
<country uri="http://localhost:9001/ws410/rest/countries/de"
isocode="de"/>
<country uri="http://localhost:9001/ws410/rest/countries/se"
isocode="se"/>
<country uri="http://localhost:9001/ws410/rest/countries/uk"
isocode="uk"/>
<country uri="http://localhost:9001/ws410/rest/countries/at"
isocode="at"/>
<country uri="http://localhost:9001/ws410/rest/countries/us"
isocode="us"/>
<country uri="http://localhost:9001/ws410/rest/countries/nl"
isocode="nl"/>
<country uri="http://localhost:9001/ws410/rest/countries/pl"
isocode="pl"/>
</countries>
HTTP Status Code
200 OK
Get a Speci c Country
Method
GET
URL
http://localhost:9001/ws410/rest/countries/uk
Body
-
Response Body
<?xml version="1.0" encoding="UTF-8"?>
<country isocode="uk">
<active>true</active>
<name>United Kingdom</name>
This is custom documentation. For more information, please visit the SAP Help Portal
146
5/27/2022
<regions/>
</country>
HTTP Status Code
200 OK
Create a New Country
Method
PUT
URL
http://localhost:9001/ws410/rest/countries/it
Body
<?xml version="1.0" encoding="UTF-8"?>
<country isocode="it">
<active>true</active>
<name>Italy</name>
<regions/>
</country>
Response Body
-
HTTP Status Code
201 Created
Delete a Country
Method
DELETE
URL
http://localhost:9001/ws410/rest/countries/it
Body
-
Response Body
-
HTTP Status Code
200 OK
Regions and Region Resources
Get All Regions
Method
GET
URL
http://localhost:9001/ws410/rest/regions
Body
-
Response Body
<?xml version="1.0" encoding="UTF-8"?>
<regions>
<region uri="http://localhost:9001/ws410/rest/regions/DE-BW"
isocode="DE-BW"/>
<region uri="http://localhost:9001/ws410/rest/regions/DE-BY"
isocode="DE-BY"/>
<region uri="http://localhost:9001/ws410/rest/regions/DE-BE"
isocode="DE-BE"/>
<region uri="http://localhost:9001/ws410/rest/regions/DE-BR"
isocode="DE-BR"/>
<region uri="http://localhost:9001/ws410/rest/regions/DE-HB"
isocode="DE-HB"/>
<region uri="http://localhost:9001/ws410/rest/regions/DE-HH"
isocode="DE-HH"/>
<region uri="http://localhost:9001/ws410/rest/regions/DE-HE"
isocode="DE-HE"/>
<region uri="http://localhost:9001/ws410/rest/regions/DE-MV"
isocode="DE-MV"/>
<region uri="http://localhost:9001/ws410/rest/regions/DE-NI"
isocode="DE-NI"/>
<region uri="http://localhost:9001/ws410/rest/regions/DE-NW"
isocode="DE-NW"/>
<region uri="http://localhost:9001/ws410/rest/regions/DE-RP"
isocode="DE-RP"/>
<region uri="http://localhost:9001/ws410/rest/regions/DE-SL"
isocode="DE-SL"/>
<region uri="http://localhost:9001/ws410/rest/regions/DE-ST"
isocode="DE-ST"/>
<region uri="http://localhost:9001/ws410/rest/regions/DE-SN"
isocode="DE-SN"/>
<region uri="http://localhost:9001/ws410/rest/regions/DE-SH"
This is custom documentation. For more information, please visit the SAP Help Portal
147
5/27/2022
isocode="DE-SH"/>
<region uri="http://localhost:9001/ws410/rest/regions/DE-TH"
isocode="DE-TH"/>
</regions>
HTTP Status Code
200 OK
Get a Speci c Region
Method
GET
URL
http://localhost:9001/ws410/rest/regions/DE-SL
Body
-
Response Body
<?xml version="1.0" encoding="UTF-8"?>
<region isocode="DE-SL">
<active>true</active>
<country uri="http://localhost:9001/ws410/rest/countries/de"
isocode="de"/>
<name>Saarland</name>
</region>
HTTP Status Code
200 OK
Create a New Region
Method
PUT
URL
http://localhost:9001/ws410/rest/regions/sl
Body
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<region isocode="sl">
<active>true</active>
<name>Slask</name>
<country isocode="pl"/>
</region>
Response Body
-
HTTP Status Code
201 Created
Delete a Region
Method
DELETE
URL
http://localhost:9001/ws410/rest/regions/sl
Body
-
Response Body
-
HTTP Status Code
200 OK
Languages and Language Resource
Get All Languages
Method
GET
URL
http://localhost:9001/ws410/rest/languages
Body
-
Response Body
<?xml version="1.0" encoding="UTF-8"?>
<languages>
<language uri="http://localhost:9001/ws410/rest/languages/en"
isocode="en"/>
<language uri="http://localhost:9001/ws410/rest/languages/de"
isocode="de"/>
</languages>
This is custom documentation. For more information, please visit the SAP Help Portal
148
5/27/2022
HTTP Status Code
200 OK
Get a Speci c Language
Method
GET
URL
http://localhost:9001/ws410/rest/languages/de
Body
-
Response Body
<?xml version="1.0" encoding="UTF-8"?>
<language isocode="de">
<active>true</active>
<fallbackLanguages/>
<name>German</name>
</language>
HTTP Status Code
200 OK
Create a New Language
Method
PUT
URL
http://localhost:9001/ws410/rest/languages/pl
Body
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<language isocode="pl">
<active>false</active>
<fallbackLanguages>
<language isocode="en">
<active>true</active>
<name>English</name>
</language>
</fallbackLanguages>
<name>Polish</name>
</language>
Response Body
-
HTTP Status Code
201 Created
Delete a Language
Method
DELETE
URL
http://localhost:9001/ws410/rest/languages/pl
Body
-
Response Body
-
HTTP Status Code
200 OK
Carts, Cart, CartEntries and CartEntry Resources
Get All Carts
Method
GET
URL
http://localhost:9001/ws410/rest/carts/
Body
-
Response Body
<?xml version="1.0" encoding="UTF-8"?>
<carts>
<cart uri="http://localhost:9001/ws410/rest/carts/00000000"
code="00000000" pk="8796093055019"/>
</carts>
HTTP Status Code
200 OK
This is custom documentation. For more information, please visit the SAP Help Portal
149
5/27/2022
Get a Speci c Cart
Method
GET
URL
http://localhost:9001/ws410/rest/carts/00000000
Body
-
Response Body
<?xml version="1.0" encoding="UTF-8"?>
<cart code="00000000" pk="8796093055019">
<calculated>true</calculated>
<currency uri="http://localhost:9001/ws410/rest/currencies/USD"
isocode="USD"/>
<date>2010-04-15T17:02:38.823+02:00</date>
<deliveryCost>0.0</deliveryCost>
<discounts/>
<entries>
<entry uri="http://localhost:9001/ws410/rest/carts/00000000/cartentries/8796093055020"
pk="8796093055020"/>
<entry uri="http://localhost:9001/ws410/rest/carts/00000000/cartentries/8796093087788"
pk="8796093087788"/>
</entries>
<net>false</net>
<paymentCost>0.0</paymentCost>
<totalDiscounts>0.0</totalDiscounts>
<totalPrice>371.15</totalPrice>
<totalTax>19.82</totalTax>
<user uri="http://localhost:9001/ws410/rest/users/anonymous"
uid="anonymous"/>
</cart>
HTTP Status Code
200 OK
Get All CartEntries
Method
GET
URL
http://localhost:9001/ws410/rest/carts/00000000/cartentries
Body
-
Response Body
<?xml version="1.0" encoding="UTF-8"?>
<cartentries>
<cartentry uri="http://localhost:9001/ws410/rest/carts/00000000/cartentries/8796093055020"
pk="8796093055020"/>
<cartentry uri="http://localhost:9001/ws410/rest/carts/00000000/cartentries/8796093087788"
pk="8796093087788"/>
</cartentries>
HTTP Status Code
200 OK
Get a Speci c CartEntry
Method
GET
URL
http://localhost:9001/ws410/rest/carts/00000000/cartentries/8796093055020
Body
-
Response Body
<?xml version="1.0" encoding="UTF-8"?>
<cartentry pk="8796093055020">
<basePrice>247.02</basePrice>
<calculated>false</calculated>
<entryNumber>0</entryNumber>
<giveAway>false</giveAway>
<info>product "HW2120-0341" with name "AMD Athlon 64 3200+
(Boxed, OPGA, "Venice")"</info>
<order uri="http://localhost:9001/ws410/rest/carts/00000000"
code="00000000" pk="8796093055019"/>
<product uri="" code="HW2120-0341"/>
<quantity>1</quantity>
<totalPrice>247.02</totalPrice>
<unit uri="http://localhost:9001/ws410/rest/units/pieces"
code="pieces"/>
</cartentry>
HTTP Status Code
200 OK
This is custom documentation. For more information, please visit the SAP Help Portal
150
5/27/2022
Add a Product to Cart
Method
POST
URL
http://localhost:9001/ws410/rest/carts/00000000/cartentries
Body
<cartentry>
<product code="31303">
<catalogVersion version="Online">
<catalog id="clothescatalog"/>
</catalogVersion>
</product>
<quantity>2</quantity>
<unit code="pieces"/>
</cartentry>
Response Body
<?xml version="1.0" encoding="UTF-8"?>
<cartentry pk="8796125986860">
<basePrice>41.331</basePrice>
<calculated>true</calculated>
<entryNumber>2</entryNumber>
<giveAway>false</giveAway>
<info>product "31303" with name "Billabong Grandma Beanie
wms"</info>
<order uri="http://localhost:9001/ws410/rest/carts/00000000"
code="00000000" pk="8796093055019"/>
<product uri="" code="31303"/>
<quantity>2</quantity>
<totalPrice>82.66</totalPrice>
<unit uri="http://localhost:9001/ws410/rest/units/pieces"
code="pieces"/>
</cartentry>
HTTP Status Code
201 Created
Remove Cart Entry
Method
DELETE
URL
http://localhost:9001/ws410/rest/carts/00000000/cartentries/8796125986860
Body
-
HTTP Status Code
200 OK
Set Delivery Address
Method
PUT
URL
http://localhost:9001/ws410/rest/carts/00000000
Body
<cart code="00000000" pk="8796093055019">
<deliveryAddress pk="8796093284375"/>
</cart>
HTTP Status Code
200 OK
Related Information
Web Service API - Reference
Extended Collection API - Examples
Examples of extended collection API usage presented here include those for both root and non-root (standard) resource types. Each example is a hands-on, practical tutorial
for you to try.
Root Resource Example
1. Display all users sorted by the value of name property using descending order. Page size of 100 guarantees that all users will be shown (it may be different on
production system).
 Note
This is custom documentation. For more information, please visit the SAP Help Portal
151
5/27/2022
Other properties of user Model like pk or uid would also work here, although the order would be then different. You can also specify the ascending order by
changing the value of users_sort parameter to: users_sort=name+asc or simply users_sort=name.
If not explicitly speci ed, the default page number is 0.
http://localhost:9001/ws410/rest/users?users_size=100&users_sort=name+desc
<users>
<user uri="http://localhost:9001/ws410/rest/users/tbullet" uid="tbullet"/>
<user uri="http://localhost:9001/ws410/rest/users/sbrueck" uid="sbrueck"/>
<user uri="http://localhost:9001/ws410/rest/users/ppetersonson" uid="ppetersonson"/>
<user uri="http://localhost:9001/ws410/rest/users/ovh" uid="ovh"/>
<user uri="http://localhost:9001/ws410/rest/users/nvp" uid="nvp"/>
<user uri="http://localhost:9001/ws410/rest/users/mdigit" uid="mdigit"/>
<user uri="http://localhost:9001/ws410/rest/users/demo" uid="demo"/>
<user uri="http://localhost:9001/ws410/rest/users/kvitali" uid="kvitali"/>
<user uri="http://localhost:9001/ws410/rest/users/JDBC%20API%20Report%20User"
uid="JDBC API Report User"/>
<user uri="http://localhost:9001/ws410/rest/users/hweaving" uid="hweaving"/>
<user uri="http://localhost:9001/ws410/rest/users/hschweiger" uid="hschweiger"/>
<user uri="http://localhost:9001/ws410/rest/users/hjaehnig" uid="hjaehnig"/>
<user uri="http://localhost:9001/ws410/rest/users/hpneumann" uid="hpneumann"/>
<user uri="http://localhost:9001/ws410/rest/users/dkaufmann" uid="dkaufmann"/>
<user uri="http://localhost:9001/ws410/rest/users/bpoweronoff" uid="bpoweronoff"/>
<user uri="http://localhost:9001/ws410/rest/users/abrode" uid="abrode"/>
<user uri="http://localhost:9001/ws410/rest/users/ariel" uid="ariel"/>
<user uri="http://localhost:9001/ws410/rest/users/anonymous" uid="anonymous"/>
<user uri="http://localhost:9001/ws410/rest/users/ahertz" uid="ahertz"/>
</users>
The users collection size is 19.
2. Show the rst page of results (page size is set to 15).
http://localhost:9001/ws410/rest/users?users_size=15&users_sort=name+desc&users_page=0
<users>
<user uri="http://localhost:9001/ws410/rest/users/tbullet" uid="tbullet"/>
<user uri="http://localhost:9001/ws410/rest/users/sbrueck" uid="sbrueck"/>
<user uri="http://localhost:9001/ws410/rest/users/ppetersonson" uid="ppetersonson"/>
<user uri="http://localhost:9001/ws410/rest/users/ovh" uid="ovh"/>
<user uri="http://localhost:9001/ws410/rest/users/nvp" uid="nvp"/>
<user uri="http://localhost:9001/ws410/rest/users/mdigit" uid="mdigit"/>
<user uri="http://localhost:9001/ws410/rest/users/demo" uid="demo"/>
<user uri="http://localhost:9001/ws410/rest/users/kvitali" uid="kvitali"/>
<user uri="http://localhost:9001/ws410/rest/users/JDBC%20API%20Report%20User"
uid="JDBC API Report User"/>
<user uri="http://localhost:9001/ws410/rest/users/hweaving" uid="hweaving"/>
<user uri="http://localhost:9001/ws410/rest/users/hschweiger" uid="hschweiger"/>
<user uri="http://localhost:9001/ws410/rest/users/hjaehnig" uid="hjaehnig"/>
<user uri="http://localhost:9001/ws410/rest/users/hpneumann" uid="hpneumann"/>
<user uri="http://localhost:9001/ws410/rest/users/dkaufmann" uid="dkaufmann"/>
<user uri="http://localhost:9001/ws410/rest/users/bpoweronoff" uid="bpoweronoff"/>
</users>
3. Show the second (and last) page of results (page size is set to 15).
 Note
Second page presents only 4 results, because the rst page contains 15 elements and the whole collection consists of 19 elements.
http://localhost:9001/ws410/rest/users?users_size=15&users_sort=name+desc&users_page=1
<users>
<user
<user
<user
<user
</users>
uri="http://localhost:9001/ws410/rest/users/abrode" uid="abrode"/>
uri="http://localhost:9001/ws410/rest/users/ariel" uid="ariel"/>
uri="http://localhost:9001/ws410/rest/users/anonymous"
uid="anonymous"/>
uri="http://localhost:9001/ws410/rest/users/ahertz" uid="ahertz"/>
4. Show the rst page where users are sorted by uid attribute and uid starts with ad (page size is set to 5).
 Note
The value of users_query parameter is {uid} LIKE 'ad%'.
http://localhost:9001/ws410/rest/users?users_size=5&users_sort=uid+asc&users_query=%7Buid%7D%20LIKE%20'ad%25'
<users uri="http://localhost:9001/ws410/rest/users?users_size=5&users_sort=uid+asc&
users_query=%7Buid%7D%20LIKE%20'ad%25'"
xmlns:ns2="http://research.sun.com/wadl/2006/10">
<user xsi:type="employeeDTO" uid="adhocdummy" pk="8796093120516"
uri="http://localhost:9001/ws410/rest/employees/adhocdummy"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
<user xsi:type="employeeDTO" uid="admin" pk="8796093054980"
uri="http://localhost:9001/ws410/rest/employees/admin" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
</users>
Standard Resource (Non-Root) Example
The example presents that two (or more) collection properties of a resource can be manipulated at the same time using the Extended Collection API.
This is custom documentation. For more information, please visit the SAP Help Portal
152
5/27/2022
 Note
Data in this example is based on the sampledata extension data, but it was modi ed for the purpose of the example. The following products (all from hwcatalog-Online)
were added directly to the HW1200 Category (Photography, hwcatalog-Online): HW1100-0023, HW2110-0019, HW2120-0341, HW2310-1007. This modi cation presents
working of simultaneous paging of two distinct collection properties.
1. Show all elements of both collections. Sort subcategories collection by code (ascending by default) and products collection by code with descending order. There is no
need to specify page size, default page size of 20 is big enough so all elements of both collections will be displayed.
http://localhost:9001/ws410/rest/catalogs/hwcatalog/catalogversions/Online/categories/HW1200?
subcategories_sort=code&products_sort=code+desc
<category code="HW1200">
<catalogVersion version="Online" uri="http://localhost:9001/ws410/rest/catalogs/hwcatalog/catalogversions/Online"/>
<subcategories>
<subcategory uri="http://localhost:9001/ws410/rest/catalogs/hwcatalog/catalogversions/Online/categories/HW1210"
code="HW1210"/>
<subcategory uri="http://localhost:9001/ws410/rest/catalogs/hwcatalog/catalogversions/Online/categories/HW1220"
code="HW1220"/>
<subcategory uri="http://localhost:9001/ws410/rest/catalogs/hwcatalog/catalogversions/Online/categories/HW1230"
code="HW1230"/>
<subcategory uri="http://localhost:9001/ws410/rest/catalogs/hwcatalog/catalogversions/Online/categories/HW1240"
code="HW1240"/>
</subcategories>
<description>miscellaneous digital cameras</description>
<name>Photography</name>
<products>
<product uri="http://localhost:9001/ws410/rest/catalogs/hwcatalog/catalogversions/Online/products/HW2310-1007"
code="HW2310-1007"/>
<product uri="http://localhost:9001/ws410/rest/catalogs/hwcatalog/catalogversions/Online/products/HW2120-0341"
code="HW2120-0341"/>
<product uri="http://localhost:9001/ws410/rest/catalogs/hwcatalog/catalogversions/Online/products/HW2110-0019"
code="HW2110-0019"/>
<product uri="http://localhost:9001/ws410/rest/catalogs/hwcatalog/catalogversions/Online/products/HW1100-0023"
code="HW1100-0023"/>
</products>
<thumbnail uri="http://localhost:9001/ws410/rest/catalogs/hwcatalog/catalogversions/Online/medias/HW1200-22"
downloadurl="/medias/sys_master/8796102295582/fotoapparat.jpg?mime=image/jpeg&realname=fotoapparat.jpeg"
code="HW1200-22"/>
</category>
2. Leave the paging of products unchanged, but set the page size for subcategories to 2 and display the rst page of results.
http://localhost:9001/ws410/rest/catalogs/hwcatalog/catalogversions/Online/categories/HW1200?
subcategories_sort=code&subcategories_size=2&subcategories_page=0&products_sort=code+desc
<category code="HW1200">
<catalogVersion version="Online" uri="http://localhost:9001/ws410/rest/catalogs/hwcatalog/catalogversions/Online"/>
<subcategories>
<subcategory uri="http://localhost:9001/ws410/rest/catalogs/hwcatalog/catalogversions/Online/categories/HW1210"
code="HW1210"/>
<subcategory uri="http://localhost:9001/ws410/rest/catalogs/hwcatalog/catalogversions/Online/categories/HW1220"
code="HW1220"/>
</subcategories>
<description>miscellaneous digital cameras</description>
<name>Photography</name>
<products>
<product uri="http://localhost:9001/ws410/rest/catalogs/hwcatalog/catalogversions/Online/products/HW2310-1007"
code="HW2310-1007"/>
<product uri="http://localhost:9001/ws410/rest/catalogs/hwcatalog/catalogversions/Online/products/HW2120-0341"
code="HW2120-0341"/>
<product uri="http://localhost:9001/ws410/rest/catalogs/hwcatalog/catalogversions/Online/products/HW2110-0019"
code="HW2110-0019"/>
<product uri="http://localhost:9001/ws410/rest/catalogs/hwcatalog/catalogversions/Online/products/HW1100-0023"
code="HW1100-0023"/>
</products>
<thumbnail uri="http://localhost:9001/ws410/rest/catalogs/hwcatalog/catalogversions/Online/medias/HW1200-22"
downloadurl="/medias/sys_master/8796102295582/fotoapparat.jpg?mime=image/jpeg&realname=fotoapparat.jpeg"
code="HW1200-22"/>
</category>
3. Display the second page of subcategories. Set the page size for products to 3 and display the third page of results. This returns only one product, because there are 4
of them in total, and the page size is 3.
http://localhost:9001/ws410/rest/catalogs/hwcatalog/catalogversions/Online/categories/HW1200?
subcategories_sort=code&subcategories_size=2&subcategories_page=1&products_sort=code+desc&products_size=3&products_page=1
<category code="HW1200">
<catalogVersion version="Online" uri="http://localhost:9001/ws410/rest/catalogs/hwcatalog/catalogversions/Online"/>
<subcategories>
<subcategory uri="http://localhost:9001/ws410/rest/catalogs/hwcatalog/catalogversions/Online/categories/HW1230"
code="HW1230"/>
<subcategory uri="http://localhost:9001/ws410/rest/catalogs/hwcatalog/catalogversions/Online/categories/HW1240"
code="HW1240"/>
</subcategories>
<description>miscellaneous digital cameras</description>
<name>Photography</name>
<products>
<product uri="http://localhost:9001/ws410/rest/catalogs/hwcatalog/catalogversions/Online/products/HW1100-0023"
code="HW1100-0023"/>
</products>
<thumbnail uri="http://localhost:9001/ws410/rest/catalogs/hwcatalog/catalogversions/Online/medias/HW1200-22"
downloadurl="/medias/sys_master/8796102295582/fotoapparat.jpg?mime=image/jpeg&realname=fotoapparat.jpeg"
code="HW1200-22"/>
</category>
This is custom documentation. For more information, please visit the SAP Help Portal
153
5/27/2022
4. Display all usergroups without subtypes (without Company instances).
http://localhost:9001/ws410/rest/usergroups?usergroups_subtypes=false
<usergroups uri="http://localhost:9001/ws410/rest/usergroups?usergroups_subtypes=false"
xmlns:ns2="http://research.sun.com/wadl/2006/10">
<usergroup uid="admingroup" pk="8796093054981"
uri="http://localhost:9001/ws410/rest/usergroups/admingroup"/>
<usergroup uid="employeegroup" pk="8796093087749"
uri="http://localhost:9001/ws410/rest/usergroups/employeegroup"/>
<usergroup uid="customergroup" pk="8796093120517"
uri="http://localhost:9001/ws410/rest/usergroups/customergroup"/>
<usergroup uid="vjdbcReportsGroup" pk="8796093186053"
uri="http://localhost:9001/ws410/rest/usergroups/vjdbcReportsGroup"/>
<usergroup uid="cockpitgroup" pk="8796093218821"
uri="http://localhost:9001/ws410/rest/usergroups/cockpitgroup"/>
...
...
</usergroups>
 Note
Collections with an abstract element type will return the following error message:
http://localhost:9001/ws410/rest/principals?principals_subtypes=false
Query parameters[for principals] are not properly constructed.
Whole Query: select {PK} from {Principal!}
order by {pk} ASC
More details: [BadRequestException]
cannot search on abstract type 'Principal' with no-subtypes option ('!') [FlexibleSearchException]
5. Using COLNAME_query and COLNAME_subtypes for collection properties that originate from CollectionType will return an appropriate error message:
http://localhost:9001/ws410/rest/users/ahertz?addresses_query=whatever&addresses_subtypes=false
FlexibleSearch querying is not supported for: addresses collection property.
The subtyping is not supported for: addresses collection property.
6. Using the attribute name, which does not exist within the speci ed type in COLNAME_sort or COLNAME_query returns an appropriate error message:
http://localhost:9001/ws410/rest/users?users_sort=asd
Query parameters[for users] are not properly constructed.
Whole Query:
select {PK} from {User}
order by {asd} ASC
More details: [BadRequestException]
cannot search unknown field 'TableField(name='asd',langPK='null',type=User)' within type User unless you disable
checking , infoMap=TypeInfoMap for type = 8796093939794
code = User
superType = 8796093874258
itemTable = users
UPTable = usersup
LTableName = userslp
PropsTable = userprops
core fields =
itemtype = [itemtype,TypePkString,class de.hybris.platform.util.ItemPropertyValue]
creationtime = [creationtime,createdTS,class java.util.Date]
uid = [uid,UniqueID,class java.lang.String]
defaultshipmentaddress = [defaultShipmentAddress,DefaultShippingAddress,
class de.hybris.platform.util.ItemPropertyValue]
description = [description,Description,class java.lang.String]
name = [name,Name,class java.lang.String]
owner = [owner,OwnerPkString,class de.hybris.platform.util.ItemPropertyValue]
modifiedtime = [modifiedtime,modifiedTS,class java.util.Date]
defaultpaymentaddress = [defaultPaymentAddress,DefaultPaymentAddress,
class de.hybris.platform.util.ItemPropertyValue]
password = [password,Passwd,class java.lang.String]
pk = [pk,PK,class de.hybris.platform.core.PK]
unlocalized fields =
europe1pricefactory_utg = [Europe1PriceFactory_UTG,p_europe1pricefactory_utg,
class de.hybris.platform.util.ItemPropertyValue]
logindisabled = [loginDisabled,p_logindisabled,class java.lang.Boolean]
sessionlanguage = [sessionLanguage,p_sessionlanguage,
class de.hybris.platform.util.ItemPropertyValue]
ldapaccount = [ldapaccount,p_ldapaccount,class java.lang.Boolean]
lastlogin = [lastLogin,p_lastlogin,class java.util.Date]
ldapsearchbase = [ldapsearchbase,p_ldapsearchbase,class java.lang.String]
passwordanswer = [passwordAnswer,p_passwordanswer,class java.lang.String]
europe1pricefactory_upg = [Europe1PriceFactory_UPG,p_europe1pricefactory_upg,
class de.hybris.platform.util.ItemPropertyValue]
passwordquestion = [passwordQuestion,p_passwordquestion,class java.lang.String]
europe1pricefactory_udg = [Europe1PriceFactory_UDG,p_europe1pricefactory_udg,
class de.hybris.platform.util.ItemPropertyValue]
hmclogindisabled = [hmcLoginDisabled,p_hmclogindisabled,class java.lang.Boolean]
ldaplogin = [ldaplogin,p_ldaplogin,class java.lang.String]
cn = [CN,p_cn,class java.lang.String]
sessioncurrency = [sessionCurrency,p_sessioncurrency,
class de.hybris.platform.util.ItemPropertyValue]
domain = [domain,p_domain,class java.lang.String]
This is custom documentation. For more information, please visit the SAP Help Portal
154
5/27/2022
)
profilepicture = [profilePicture,p_profilepicture,
class de.hybris.platform.util.ItemPropertyValue]
dn = [DN,p_dn,class java.lang.String]
userprofile = [userprofile,p_userprofile,
class de.hybris.platform.util.ItemPropertyValue]
localized fields = []
[FlexibleSearchException]
REST Commands Tutorial
Binding commands to resources is an easy way to trigger business logic via web services. SAP Commerce web services provide commands that allow you to place an order or
to create, start, or abort a CronJob. It also enables you to create your own commands.
How to Write New Commands
Every custom command must extend the de.hybris.platform.webservices.AbstractCommand class, which implements the
de.hybris.platform.webservices.Command interface.
There are only two methods de ned in the de.hybris.platform.webservices.Command interface:
getName() - this method is used only to return a command name. It is de ned in the de.hybris.platform.webservices.AbstractCommand class.
execute( nal RESOURCE resourceEntity, nal REQUEST requestEntity) - this method contains command logic. It should be de ned in a new class created for a
custom command.
A custom command has to be declared in platformwebservices-web-spring.xml con guration le.
The following example presents a part of the le with declarations of three commands:
createCronJobCommand
startCronJobCommand
abortCronJobCommand
<bean id="createCronJobCommand" class="de.hybris.platform.webservices.resources.commands.CreateCronJobCommand">
<property name="objectGraph" ref="genericGraph"/>
</bean>
<bean id="startCronJobCommand" class="de.hybris.platform.webservices.resources.commands.StartCronJobCommand">
<property name="objectGraph" ref="genericGraph"/>
</bean>
<bean id="abortCronJobCommand" class="de.hybris.platform.webservices.resources.commands.AbortCronJobCommand">
<property name="objectGraph" ref="genericGraph"/>
</bean>
A command may have several or no properties, like objectGraph.
How to Add a Command to an Existing Resource
Each resource has two command handlers that reference to lists of commands:
postCommandHandler for POST method
putCommandHandler for PUT method
Different commands can be accessible depending on which HTTP method is used.
In the following example two commands are available when using PUT method: startCronJobCommand and abortCronJobCommand, and only one command, that is
createCronJobCommand is available when using POST method.
<bean id="cronJobResource" class="de.hybris.platform.cronjob.resource.CronJobResource"
scope="prototype" parent="abstractResource">
<property name="putCommandHandler" ref="cronJobResourcePutCommands"/>
<property name="postCommandHandler" ref="cronJobResourcePostCommands"/>
</bean>
<bean id="cronJobResourcePutCommands" class="de.hybris.platform.webservices.DefaultCommandHandler">
<property name="allCommands">
<list>
<ref bean="startCronJobCommand"/>
<ref bean="abortCronJobCommand"/>
</list>
</property>
</bean>
<bean id="cronJobResourcePostCommands" class="de.hybris.platform.webservices.DefaultCommandHandler">
<property name="allCommands">
<list>
<ref bean="createCronJobCommand"/>
</list>
</property>
</bean>
This is custom documentation. For more information, please visit the SAP Help Portal
155
5/27/2022
How to De ne Security Constrains for a Resource
Security constraints for a command depend on a associated resource. They are de ned in project.properties le for the platformwebservices extension.
For enabling and disabling security the webservices.security option is used.
Security constrains can be con gured in two ways:
for a package and its sub-packages:
webservices.security.de.hybris.platform=employeegroup[GET]; customergroup[GET,PUT,POST]
The example presents security constrains that allow all users from employeegroup and customergroup to access resources contained in de.hybris.platform package
and all its sub-packages. Users from employeegroup group are restricted to use only GET method. Users from the customergroup can access resources using GET,
PUT or POST method.
for a resource:
webservices.security.de.hybris.platform.core.resource.order.CartResource=anonymous[POST, PUT]
In the example, users from the anonymous group are allowed to access the CartResource using HTTP POST or PUT methods.
Related Information
WebService API - Reference
Customizing Resources and DTOs
By generating default resource and DTO implementations for each type in SAP Commerce, complete RESTful CRUD access is offered. However, if the default behavior is not
sufficient for a user, it is always possible to override it with a custom implementation.
Custom DTO
Replace the word Speci c with an extension's type name you wish to customize.
CustomTypeDTO.java
@GraphNode(target = SpecificTypeModel.class, factory = GenericNodeFactory.class, uidProperties="pk")
@XmlRootElement(name = "Customtype")
@SuppressWarnings("PMD")
public class CustomTypeDTO extends SpecificTypeDTO
{
private java.lang.String _ownField;
/**
* @param ownField
*
the _ownField to set
*/
public void set_ownField(final java.lang.String ownField)
{
_ownField = ownField;
}
/**
* @return the _ownField
*/
public java.lang.String get_ownField()
{
return _ownField;
}
}
CustomTypesDTO.java
@XmlRootElement(name = "Customtype")
@SuppressWarnings("PMD")
public class CustomTypesDTO extends SpecificTypesDTO
{
//
}
Custom Resource
CustomTypeResource.java
@SuppressWarnings("PMD")
public class CustomTypeResource extends AbstractYResource<SpecificTypeModel>
{
private String arg;
/**
This is custom documentation. For more information, please visit the SAP Help Portal
156
5/27/2022
* <i>Generated constructor</i> - for generic creation.
*/
public CustomTypeResource()
{
super("CustomType");
}
/**
* Convenience method which just delegates to {@link #getResourceValue()}
*/
public SpecificTypeModel getSpecificTypeModel()
{
return super.getResourceValue();
}
/**
* Gets the {@link SpecificTypeModel} resource which is addressed by current resource request.
* @see de.hybris.platform.webservices.AbstractYResource#readResource(String)
*/
@Override
protected SpecificTypeModel readResource(final String resourceId) throws Exception
{
return serviceLocator.getModelService().get(PK.parse(resourceId));
}
/**
* Convenience method which just delegates to {@link #setResourceValue(SpecificTypeModel)}
*/
public void setSpecificTypeModel(final SpecificTypeModel value)
{
super.setResourceValue(value);
}
@GET
public Response getPrice()
{
final CustomTypeDTO dto = new CustomTypeDTO();
dto.set_ownField("fieldValue in " + getArg());
dto.setUri("from " + this.getClass().getName());
getResponse().entity(dto);
return getResponse().build();
}
/**
* custom arg
*/
public void setArg(final String arg)
{
this.arg = arg;
}
/**
* custom arg
*/
public String getArg()
{
return arg;
}
}
Collection of Resources
CustomTypesResource.java
@Path("/Customtypes")
@SuppressWarnings("PMD")
public class CustomTypesResource extends AbstractCollectionResource<Collection<CustomTypeDTO>>
{
/**
* custom get method
*/
@GET
public Response getCustomType()
{
final CustomTypeDTO dto = new CustomTypeDTO();
dto.set_ownField("fieldValue all");
dto.setUri("custom uri alll");
getResponse().entity(dto);
return getResponse().build();
}
/**
* Generated getter for sub resource of type {@link SpecificTypeResource} for current root resource
*/
@Path("{Customtype}")
public AbstractYResource getCustomTypeResource(@PathParam("Customtype") final String resourceKey)
{
final CustomTypeResource resource = resourceCtx.getResource(CustomTypeResource.class);
resource.setResourceId(resourceKey);
resource.setParentResource(this);
resource.setArg(resourceKey);
return resource;
}
This is custom documentation. For more information, please visit the SAP Help Portal
157
5/27/2022
/**
* @param composedTypeName
*/
public CustomTypesResource(final String composedTypeName)
{
super("CustomTypesResource");
}
public CustomTypesResource()
{
super("CustomTypesResource");
}
/**
*
* access to custom subresource
*/
@Path("/myurl/{language}")
public AbstractYResource getCustomType(@PathParam("language") final String resourceKey)
{
final LanguageResource resource = resourceCtx.getResource(LanguageResource.class);
resource.setResourceId(resourceKey );
resource.setParentResource(this);
return resource;
}
}
Accessing Virtual Resources
The following call via web service client:
http://localhost:9001/aspecttraining/rest/diagnostic/
results in output similar to this:
<virtual time="1283843533629" xmlns:ns2="http://research.sun.com/wadl/2006/10">
<extensions>core,hmc,paymentstandard,deliveryzone,commons,lucenesearch,impex,validation,
variants,task,ldap,europe1,category,workflow,processing,catalog,virtualjdbc,platformservices,comments,
cockpit,mcc,advancedsavedquery,admincockpit,aspecttraining,
</extensions>
</virtual>
Hints and Pitfalls
Currently the platformwebservices extension contains some custom DTOs and resources.
Rede ning Custom DTOs and Resources
It is possible to rede ne custom DTOs and resources again through the custom extension of web service nature. In such a situation, when you upgrade to a newer version of
SAP Commerce, some custom DTOs and Resources from platformwebservices extension may be changed. Then you may get compilation errors, because the les from your
custom extension are taken into account and those from platformwebservices extension are omitted. The problem can be solved by merging information given in the new
custom le from the platformwebservices extension to your le located in the custom extension. For more details, see Web Services Key Features and Implementation
Details.
Related Information
WebService Resource Concept
WebService DTO Concept
Installer Platform Plugin
The Platform Plugin is a standard Gradle plugin. It provides an API for managing Commerce Platform instances, as well as Tomcat instances in Gradle build les, in an easy,
and readable way.
Enabling the Platform Plugin
You enable the Platform plugin in a Gradle build le. Once you have enabled the plugin, you can set up and con gure any existing Commerce Platform instance. To enable the
Platform plugin, use the following method:
apply plugin: 'platform-plugin'
Environment Variables
DRIVER_JAR_PATH is a path to the jdbc driver jar that must be copied into the Platform home lib/dbdrivers directory in some special cases when working with the
installer.
Gradle Project Properties
This is custom documentation. For more information, please visit the SAP Help Portal
158
5/27/2022
The Platform plugin may use a project property passed to the build script to determine the Platform home:
-Pplatform_home=/path/to/bin/platform
This variable is useful in the development mode when testing plugin separately or if an installer project that is using the Platform plugin is outside of SAP Commerce. Please
note that the installer install scripts use this property via the -P option - the -Pplatform_home switch may be used only when using gradle directly.
Setting Up the Platform Using the Platform Object
The following paragraph includes information about Platform Plugin variables and its methods.
Platform Plugin Variables
The Platform plugin enriches the standard Gradle project object with the following variables:
Variable
Description
platformHome
The absolute path to the Commerce Platform directory
Type: String
Examples:
/Users/foo/commerce-suite-5.4/hybris/bin/platform
C:\foo\commerce-suite-5.4\hybris\bin\platform
installerHome
The absolute path to the root directory of the installer project
Type: String
installerWorkDir
The work directory of the installer.
Type: String
platformConfig
The absolute path to the SAP Commerce con g directory
Type: String
Examples:
/Users/foo/commerce-suite-5.4/hybris/config
C:\foo\commerce-suite-5.4\hybris\config
suiteHome
The absolute path to the SAP Commerce directory
Type: String
Examples:
/Users/foo/commerce-suite-5.4
C:\foo\commerce-suite-5.4
platformFactory
The platformFactory object used to instantiate the HybrisPlatform and
HybrisPlatformRole objects
Type: HybrisPlatformFactory
tomcat
The Tomcat builder object
Type: HybrisTomcat
hsqldb
The HSQLDB management object that makes it possible to run the HSQLDB as a separate
process.
Type: HybrisHsqldb
Platform Plugin Methods
The Platform plugin provides methods that are accessible directly from the build le so that they can be used easily with the HybrisPlatform and
HybrisPlatformRole objects. The Platform plugin provides the following methods:
Method
Description
platform(Closure closure)
Used to set up and instantiate the HybrisPlatform object.
platformRole(Closure closure)
Used to set up and instantiate the HybrisPlatformRole object.
HybrisPlatformFactory, HybrisPlatform and HybrisPlatformRole Objects
This is custom documentation. For more information, please visit the SAP Help Portal
159
5/27/2022
The standard Gradle project object includes a special object, the HybrisPlatformFactory object; it sets up and creates the HybrisPlatform and
HybrisPlatformRole objects.
The HybrisPlatformFactory object can be accessed directly as a platformFactory or through the project object as project.platformFactory.
HybrisPlatform Object
The HybrisPlatform object provides methods to con gure the Platform, such as the con guration of databases, extensions, local properties, and clusters. It also provides
convenient methods to write con gurations to the appropriate les, compile and initialize the Platform, and run the Platform on Tomcat.
To create a simple Platform object, use the following code:
createPlatform Method
def myPlatform = platformFactory.createPlatform()
The code creates a simple Platform object called myPlatform. The object is con gured with the required default settings, runs on an HSQLDB database, and has Platform
extensions set only.
The following table presents the methods provided with the HybrisPlatform object:
Method
Description
myPlatform.setup()
Writes the setup to a con g folder.
myPlatform.build()
Initializes the Platform.
myPlatform.runInBackground()
Runs the Platform on a Tomcat instance in background mode.
The Platform plugin also provides the platform shortcut method, accessible directly from the build le. It creates an instance of the HybrisPlatform object, and allows
you to con gure it. The method takes <Closure> as a parameter, as shown in the following example:
dbSetup
def myPlatform = platform {
dbSetup {
dbType 'mysql'
dbUrl 'jdbc:mysql://localhost/hybris?useConfigs=maxPerformance&characterEncoding=utf8'
dbUser 'dbuser'
dbPassword 'passwd'
}
extensions {
scanPath '/Users/foo/backoffice-extensions'
extensionNames 'hmc', 'backoffice'
}
localProperties {
property 'media.legacy.prettyURL', 'true'
}
}
The code example does the following:
Creates an instance of the HybrisPlatform object that is con gured to use a MySQL database.
Con gures the Platform to use the hmc and backoffice extension sets (using an additional scan path to search for the extensions in the
/Users/foo/backoffice-extensions folder).
Adds the <media.legacy.prettyURL> property to the local.properties le.
You can also con gure the HybrisPlatform object to be a node in a cluster. The following code excerpt shows how to do it:
def myPlatform = platform {
dbSetup {
dbType 'mysql'
dbUrl 'jdbc:mysql://localhost/hybris?useConfigs=maxPerformance&characterEncoding=utf8'
dbUser 'dbuser'
dbPassword 'passwd'
}
extensions {
scanPath '/Users/foo/backoffice-extensions'
extensionNames 'hmc', 'backoffice'
}
This is custom documentation. For more information, please visit the SAP Help Portal
160
5/27/2022
clusterSettings {
id '1'
maxId '5'
udpMulticast()
}
}
For more detailed information about cluster settings, see:
Advanced Cluster Settings API
Clustering
HybrisPlatform API
In this paragraph you can nd detailed information about the HybrisPlatform API.
dbSetup(Closure) sets up the database connection. Note that the database must already exist. It takes <Closure> as a parameter in which you can set the
required information using the following methods:
dbType(String): The type of the database. The supported values are <mysql>, <oracle>, <sqlserver>, <sap>, and <hsqldb>.
dbUrl(String): The URL to connect to the database.
dbUser(String): Database user name.
dbPassword(String): User database password.
dbTablePrefix(String): Pre x for the database table.
dbDriverJar(String): An optional path to the custom JDBC driver jar.
dbSetup
dbSetup {
dbType 'mysql'
dbUrl 'jdbc:mysql://localhost/hybris?useConfigs=maxPerformance&characterEncoding=utf8'
dbUser 'myDbUser'
dbPassword 'somePassword'
dbTablePrefix 'foobar'
dbDriverJar '/tmp/mysql-connector-java-5.1.31.jar'
}
localProperties(Closure) is used to specify custom properties. It takes <Closure> as a parameter in which you can set the required information using the
following methods:
property(String, String): Property key, property value.
properties(Map<String, String>): Map of properties.
customConfig(String): Name of the le used to store custom settings. All settings are merged.
 Caution
The settings speci ed in this le overwrite the settings speci ed in a recipe.
localProperties
localProperties {
property 'foo.key', 'foo.value'
properties(
'bar.key': 'bar.value',
'baz.key': 'baz.value'
)
customConfig 'mySettings.properties'
}
extensions(Closure) is used to add a custom set of extensions to the con gured Platform. It takes <Closure> as a parameter to set the required information
using the following methods:
extensionNames(String...): Extension names expressed as <varargs>.
extName(String): Extension name.
extensionDirs(String...): Extension directories expressed as <varargs>.
extDir(String): Extension directory.
scanPath(String): Directory in which the Platform looks for the extensions provided by the extensionNames method or the extName method. Note that
the <autoload> option must be set to <false>, that is, it must be disabled.
scanPath(String, Integer): Directory in which the Platform looks for extensions provided by the extensionNames method or the extName method.
Note that the <autoload> option must be set to <true>, that is, it must be enabled and the depth option set to a speci ed scan depth.
scanPathWithAutoLoad(String): Directory in which the Platform looks for the extensions provided by the extensionNames method or the extName
method. Note that the <autoload> option must be set to <true>, that is, it must be enabled.
scanPathWithAutoLoad(String, Integer): Directory in which the Platform looks for the extensions provided by the extensionNames method or the
extName method. Note that the <autoload> option must be set to <true>, that is, it must be enabled).
disableDefaultScanPath(): It disables the default scan path (<$HYBRIS_BIN_DIR>).
This is custom documentation. For more information, please visit the SAP Help Portal
161
5/27/2022
defaultScanPathWithAutoLoad(): It forces the default scan path (<$HYBRIS_BIN_DIR>) to have the <autload> option set to <true>.
defaultScanPathWithAutoLoad(Integer): It forces the default scan path (<$HYBRIS_BIN_DIR>) to have the <autload> option set to <true> with a
speci ed scan depth.
webApp(Closure): Deployment of external webapps. It takes <Closure> as a parameter to set the required information using the following methods:
context(String): Path to context.xml le.
contextRoot(String): Root context of the webapp.
path(String): Path to the external war le.
customConfig(String): Name of the le used to store custom settings. All settings are merged.
 Caution
The settings speci ed in this le overwrite the settings speci ed in a recipe.
extensions
extensions {
scanPath '/Users/foo/additional-extensions1'
scanPathWithAutoLoad '/Users/foo/load-all-extensions'
extensionNames 'foo', 'bar', 'baz'
extName 'one'
extName 'two'
extensionDirs '/Users/foo/ext1', '/Users/foo/ext2'
extDir '/Users/foo/ext3'
extDir '/Users/foo/ext4'
webApp {
context '/foo/bar/context.xml'
contextRoot 'foo'
path '/one/two/three.war'
}
customConfig 'myExtensions.xml'
}
mediaStorageSettings(Closure) is used to specify the media storage con guration. By default, the Commerce Platform is con gured to use local media
storage out-of-the-box, therefore no special con guration is required. This method takes <Closure> as a parameter to set the required information using the
following methods:
defaultHashingDepth(Integer): Speci es the number of subdirectories permitted in a storage. Permitted values are 0 to 4.
localStorageStrategy(Closure): Sets up the local media storage. This method takes <Closure> as a parameter to set the required information using
the following methods:
defaultStorageStrategy(): Speci es the storage strategy to be used as the default storage strategy for the entire SAP Commerce.
defaultUrlStrategy(): Sets localMediaWebURLStrategy as the default URL storage strategy.
folders(String...): Speci es the storage strategy to be used as the strategy for the folders. This method takes the variable argument list of
folder quali ers.
foldersWithUrlStrategy(String...): Sets the storage strategy as a strategy, as well as the localMediaWebURLStrategy as the URL
strategy for folders. This method takes the variable argument list of folder quali ers.
dir(String): Sets the custom directory to be used as the default storage directory.
mediaStorageSetting
// Remaping media dir to /tmp/myMedias - useful for cluster setup
mediaStorageSettings {
localStorageStrategy {
dir '/tmp/myMedias'
}
}
// Setting Local Storage strategy for two folders. This make sense in case when other strategy is set as default.
mediaStorageSettings {
localStorageStrategy {
folders 'folderOne', 'folderTwo'
}
}
s3StorageStrategy: Sets up the s3 media storage. This method takes <Closure> as a parameter to set the required information using the following
methods:
defaultStorageStrategy(): Sets the speci ed storage strategy as the default storage strategy for the entire SAP Commerce.
defaultUrlStrategy(): Sets s3MediaUrlStrategy as the default URL storage strategy. If you don't set this option, the
localMediaWebURLStrategy are used by default.
folders(String...): Sets this storage strategy as the strategy for the folders. This method takes the variable argument list of folder quali ers.
foldersWithUrlStrategy(String...): Sets the storage strategy as a strategy, as well as the s3MediaUrlStrategy as the URL strategy for
the folders. This method takes the variable argument list of the folder quali ers.
accessKey(String): Sets the access key for the S3 account.
secretAccessKey(String): Sets the secret access key for the S3 account.
endPoint(String): Sets the end point URL for the S3 storage.
urlSigned(boolean): Speci es if the S3 URL strategy will produce signed URLs. This option is only applied when the defaultUrlStrategy() is
used.
timeToLiveInMinutes(int): Speci es the length of time, in minutes, for which the signed URL is valid. This option is only applied when
defaultUrlStrategy() and urlSigned(true) are used.
This is custom documentation. For more information, please visit the SAP Help Portal
162
5/27/2022
urlUnsignedHttps(boolean): Speci es if the unsigned URL uses HTTPS. This option is only applied when defaultUrlStrategy() and
urlSigned(false) are used.
urlUnsignedVirtualHost(boolean): Speci es if the unsigned URL uses virtual hosting. This option is only applied when
defaultUrlStrategy() and urlSigned(false) are used.
s3StorageStrategy
// Setting S3 Storage Strategy as default (standard local URL strategy)
mediaStorageSettings {
s3StorageStrategy {
defaultStorageStrategy()
accessKey 'SOME-KEY'
secretAccessKey 'SOME-SECRET'
endPoint 'http://somewhere.com/'
}
}
// Setting S3 Storage Strategy for two folders
mediaStorageSettings {
s3StorageStrategy {
accessKey 'SOME-KEY'
secretAccessKey 'SOME-SECRET'
endPoint 'http://somewhere.com/'
folders 'folderOne', 'folderTwo'
}
}
// Setting S3 Storage Strategy as default (S3 Url strategy with default settings)
mediaStorageSettings {
s3StorageStrategy {
defaultStorageStrategy()
defaultUrlStrategy()
accessKey 'SOME-KEY'
secretAccessKey 'SOME-SECRET'
endPoint 'http://somewhere.com/'
}
}
azureStorageStrategy(Closure): Sets up the Windows Azure Blob storage strategy. This method takes <Closure> as a parameter to set the required
information using the following methods:
defaultStorageStrategy(): Sets the speci ed storage strategy as the default storage strategy for the entire system.
defaultUrlStrategy(): Sets the windowsAzureBlobURLStrategy as the default URL storage strategy. If you don't set this option, the
localMediaWebURLStrategy is used as the default strategy.
folders(String...): Sets this storage strategy as the strategy for the folders. This method takes the variable argument list of folder quali ers.
foldersWithUrlStrategy(String...): Sets the storage strategy as a strategy, as well as windowsAzureBlobURLStrategy as the URL
strategy for the folders. This method takes the variable argument list of the folder quali ers.
connection(String): Sets up the connection string for the Azure account.
publicBaseUrl(String): Sets up the public base URL for the Azure account.
containerAddress(String): Speci es the container address in which all media will be stored.
azureStorageStrategy
// Setting Windows Azure Blob storage strategy as default (standard local URL strategy)
mediaStorageSettings {
azureStorageStrategy {
defaultStorageStrategy()
connection 'CONNECTION-STRING'
containerAddress 'MY-CONTAINER'
publicBaseUrl 'some-account.blob.core.windows.net'
}
}
// Setting Windows Azure Blob storage for two folders
mediaStorageSettings {
azureStorageStrategy {
connection 'CONNECTION-STRING'
containerAddress 'MY-CONTAINER'
publicBaseUrl 'some-account.blob.core.windows.net'
folders 'folderOne', 'folderTwo'
}
}
// Setting Windows Azure Blob storage strategy as default (Windows Azure Url strategy with default settings)
mediaStorageSettings {
azureStorageStrategy {
defaultStorageStrategy()
defaultUrlStrategy()
connection 'CONNECTION-STRING'
containerAddress 'MY-CONTAINER'
publicBaseUrl 'some-account.blob.core.windows.net'
}
}
gridFsStorageStrategy(Closure): Speci es the Mongo GridFS storage strategy. This method takes <Closure> as a parameter to set the required
information using the following methods:
defaultStorageStrategy(): Sets this storage strategy as default one for entire system.
defaultUrlStrategy(): Sets localMediaWebURLStrategy as the default URL storage strategy. The GridFS storage doesn't provide a special
URL strategy, therefore this method isn't mandatory.
folders(String...): Sets this storage strategy as a strategy for folders. This method takes the variable argument list of the folder quali ers.
This is custom documentation. For more information, please visit the SAP Help Portal
163
5/27/2022
foldersWithUrlStrategy(String...): Sets the storage startegy as a strategy, as well as localMediaWebURLStrategy as the URL strategy
for the folders. This method takes the variable argument list of the folder quali ers.
host(String): Sets the host for the MongoDB database. The default value is <localhost>.
port(String): Speci es the port for the MongoDB database. The default value is <27017>.
dbName(String): Speci es the name of the database. The default value is hybris_storage.
userName(String): Speci es the user name for the MongoDB database. The default value is <empty>.
password(String): Speci es the password for the MongoDB database. The default value is <empty>.
gridFsStorageStrategy
// Setting Mongo GridFS storage strategy as default
mediaStorageSettings {
gridFsStorageStrategy {
defaultStorageStrategy()
host '10.0.0.10'
port '9090'
userName 'some-user'
password 'password'
}
}
// Setting Mongo GridFS storage strategy for two folders
mediaStorageSettings {
gridFsStorageStrategy {
host '10.0.0.10'
port '9090'
userName 'some-user'
password 'password'
folders 'folderOne', 'folderTwo'
}
}
clusterSettings(Closure): Used to specify the cluster node settings. This method takes <Closure> as a parameter to set the required information using the
following methods:
id(String): ID of a node.
maxId(String): Max ID for the entire cluster.
jGroups(Closure): Setting for the jGroups communication.
jGroups(): Default settings for the jGroups.
udpMulticast(Closure): Settings for the UDP multicast communication.
udpMulticast(): Default settings for the UDP multicast.
udpUnicast(Closure): Settings for the UDP unicast communication.
setup(): Stores the properties and extensions settings in proper les, as well as optionally copies custom JDBC driver jar to the Platform lib/dbdriver/
directory.
build(): Executes the ant clean all command on the underlying Platform.
initialize(): Executes the ant initialize command on the underlying Platform.
initializeTestSystem(): Executes the ant yunitinit command on the underlying Platform.
executeAntTarget(String): Enables the execution of any ant target supported by underlying build.xml le in the Platform.
executeAntTarget(String, String): Enables the execution of any ant target supported by underlying build.xml le in the Platform with additional ant
options.
ant targets
executeAntTarget 'clean all initialize'
executeAntTarget 'alltests -Dtestclasses.extensions=core'
executeAntTarget 'initialize', '-Xmx2048m -XX:MaxPermSize=756M'
start(): Starts the con gured Platform on a Tomcat in interactive mode.
startInDebug(): Starts the con gured Platform on a Tomcat in interactive and debug modes.
startInBackground(): Starts the con gured Platform on a Tomcat in background mode.
stopInBackground(): Stops the Platform running on a Tomcat in background mode.
createProductionArtifacts(): Creates production artifacts that are stored in a temp directory of the Platform.
importImpexFromContent(String content): Imports impex content kept in a string variable.
def importContent = '''
INSERT_UPDATE MediaFormat;qualifier[unique=true]
;foo;
;bar;
;baz;
'''
importImpexFromContent(importContent)
importImpexFromResource(String resourcePath): Imports impex content kept in a resource.
def resource = '/tmp/myImport.impex'
importImpexFromResource(resource)
executeScriptFromContent(String content, String scriptType) : Executes the content of the script. Valid script types are groovy, js, bsh.
This is custom documentation. For more information, please visit the SAP Help Portal
164
5/27/2022
def script = '''
flexibleSearchService.search("SELECT {PK} FROM {MediaFormat}").getResult().forEach {
println it.qualifier
}
''' executeScriptFromContent(content, 'groovy')
executeScriptFromResource(String resourcePath): Executes a script from the existing resource. Keep in mind that the resource le must have proper le
extension (groovy, js or bsh).
def resource = '/tmp/myScript.groovy'
executeScriptFromResource(resource'
Testing Capabilities
The HybrisPlatform object includes an API for easy test execution.
Simply, inside your recipe, specify which tests and from which set of extensions you want to run:
def pl = platform {
tests {
extensions 'foo', 'bar'
annotations 'UnitTest', 'IntegrationTest'
packages 'foo.bar.baz.*'
reportDir '/tmp/junit'
}
}
pl.runTests()
The API includes the following methods:
tests(Closure): It allows you to con gure test execution. This method takes <Closure> as a parameter to set the required information using the following
methods:
extensions(String...): Narrows test execution only to the names of provided extension.
annotations(String...): Narrows test execution only to tests annotated with annotations. The options allowed are <UnitTest>, <IntegrationTest>,
<PerformanceTest>, <DemoTest>
packages: Narrows test execution only to provided packages.
excludedPackages: Allows you to exclude packages from test execution.
reportDir: Allows you to set different report directory. The default directory is log/junit/ in the Platform main directory.
webTests(Closure): It allows you to con gure execution of web tests. This method takes <Closure> as a parameter to set the required information using the
following methods:
extensions(String...): Narrows test execution only to the names of provided extension.
annotations(String...): Narrows test execution only to tests annotated with annotations. The options allowed are <UnitTest>, <IntegrationTest>,
<PerformanceTest>, <DemoTest>
packages: Narrows test execution only to provided packages.
excludedPackages: Allows you to exclude packages from test execution.
reportDir: Allows you to set a different report directory. The default directory is a log/junit/ in the Platform main directory.
HybrisPlatformRole Object
Commerce Platform roles make it possible to set up templates that you can use to create instances, set them up in a local cluster and spawn them, all in one action.
The HybrisPlatformRole object provides methods to con gure all aspects of the Platform role, such as the con guration of databases, extensions, and local properties.
It also provides convenient methods for writing con gurations to the appropriate les, compiling and initializing the Platform role, as well as creating instances of the role.
To create a Platform role, use the following code:
Code to create a hybris Platform Role
def myRole = platformFactory.createRole {
roleName 'myRole1'
}
The code creates a simple myRole object called myRole1. The object is con gured with default settings, runs on an HSQLDB database, and has Platform extensions set
only.
This is custom documentation. For more information, please visit the SAP Help Portal
165
5/27/2022
The following table presents the methods provided with the HybrisPlatformRole object:
Method
Description
myRole.setup
Creates the role physically on disk and writes the setup to the role's config folder.
myRole.build
Compiles all binaries that are to be shared between the role instances.
myRole.initialize
Initializes the database.
The following code excerpt shows how to create a simple role that runs on a MySQL database with two instances. The role uses jgroups for cluster communication with the
platformRole shortcut method, which, similar to the platform method, is accessible from the build le.
def myRole = platformRole {
roleName 'backOfficeRole'
dbSetup {
dbType 'mysql'
dbUrl 'jdbc:mysql://localhost/hybris?useConfigs=maxPerformance&characterEncoding=utf8'
dbUser 'dbuser'
dbPassword 'passwd'
}
extensions {
scanPath '/Users/foo/backoffice-extensions'
extensionNames 'hmc', 'backoffice'
}
}
def instanceOne = myRole.createInstance {
standardPortsFrom 9011
clusterSettings {
id '0'
maxId '2'
jGroups()
}
}
def instanceTwo = myRole.createInstance {
standardPortsFrom 9021
clusterSettings {
id '1'
maxId '2'
jGroups()
}
}
myRole.setup()
myRole.build()
myRole.initialize()
instanceOne.setup()
instanceTwo.setup()
instanceOne.startInBackground()
instanceTwo.startInBackground()
The code example provided does the following:
1. Creates a Commerce Platform role.
2. Creates two instances of the HybrisPlatform role to run on a different set of ports on nodes of the same cluster.
3. Stores the con guration on disk.
4. Spawns the instances on local Tomcats.
HybrisPlatformRole API
This section provides detailed information about the HybrisPlatformRole API.
roleName(String): Unique role name.
dbSetup(Closure): For information on the dbSetup method, see the dbSetup Method of the HybrisPlatform API.
This is custom documentation. For more information, please visit the SAP Help Portal
166
5/27/2022
localProperties(Closure): Used to specify custom properties. This method takes <Closure> as a parameter in which you can de ne properties using the
following methods:
property(String, String): Property key, property value
properties(Map<String, String>): Map of properties
customConfig(String): Name of the le used to store custom settings. All settings are merged. Settings in a le overwrite settings from recipe.
localProperties
localProperties {
property 'foo.key', 'foo.value'
properties(
'bar.key': 'bar.value',
'baz.key': 'baz.value'
)
customConfig 'mySettings.properties'
}
extensions(Closure): Used to specify a custom set of extensions to be part of the con gured Platform. This method takes <Closure> as a parameter to set the
required information using the following methods:
extensionNames(String...): Extensions names expressed as <varargs>.
extName(String): Extension name.
extensionDirs(String...): Extensions directories expressed as <varargs>.
extDir(String): Extension directory.
scanPath(String): Directory in which the Platform looks for the extensions provided by the extensionNames method or the extName method
(<autoload> option set to <false>).
scanPathWithAutoLoad(String): Directory in which the Platform looks for the extensions provided by the extensionNames method or the extName
method (<autoload> option set to <true>).
customConfig(String): Name of the le used to store custom settings. All settings are merged.
extensions
extensions {
scanPath '/Users/foo/additional-extensions1'
scanPathWithAutoLoad '/Users/foo/load-all-extensions'
extensionNames 'foo', 'bar', 'baz'
extName 'one'
extName 'two'
extensionDirs '/Users/foo/ext1', '/Users/foo/ext2'
extDir '/Users/foo/ext3'
extDir '/Users/foo/ext4'
customConfig 'myExtensions.xml'
}
mediaStorageSettings(Closure): For detailed information, see the mediaStorageSettings Method of the HybrisPlatform API.
setup(): Stores the properties and extensions settings into the appropriate les of a role, and optionally copies the custom JDBC driver jar to the Platform
lib/dbdriver/ directory.
build(): Compiles all common to nodes binaries.
initialize(): Initializes the database for the role.
initializeTestSystem(): Initializes the test system for the role.
update(): Updates the database for the role.
createProductionArtifacts(): Creates the production artifacts, which are stored in a temp directory of the role.
createInstance(Closure): Creates a new instance of the role. This method takes <Closure> as a parameter in which you can set the required information as
described in RoleInstance API.
RoleInstance API
The following paragraph provides information about the methods the RoleInstance API consists of.
The RoleInstance API methods are:
httpPort(int): Tomcat HTTP port
sslPort(int): Tomcat SSL port
ajpPort(int): AJP port
jmxPort(int): JMX port
jmxServerPort(int): JMX server port
standardPortsFrom(int): Makes it possible to set all the above-mentioned ports at once, starting from the speci ed port. For example: If you start from port
9001, then the httpPort is set to 9001 and all succeeding ports are incremented by 1 up to 9006. The ports are set in the following order: sslPort, ajpPort, jmxPort, and
jmxServerPort.
cluster(Closure): Used to specify the settings for the cluster node. This method takes <Closure> as a parameter to set all necessary information by use of the
following methods:
This is custom documentation. For more information, please visit the SAP Help Portal
167
5/27/2022
id(String): ID of a node.
maxId(String): Max ID for the entire cluster.
jGroups(Closure): Settings for jGroups communication.
jGroups(): Default settings for jGroups.
udpMulticast(Closure): Settings for UDP multicast communication.
udpMulticast(): Default settings for UDP multicast.
udpUnicast(Closure): Settings for UDP unicast communication.
Advanced Cluster Settings API
Setting up a cluster can be complicated, especially on a single-developer machine. The Platform Plugin API facilitates setting up a cluster.
To con gure a cluster node, use the cluster(Closure) method; it is available in the HybrisPlatform and PlatformInstance objects.
Before con guring a cluster node, select the communication mechanism you want to use:
jGroups
UDP Multicast
UDP Unicast
jGroups Con guration
To con gure a jGroups-enabled node, use the following code:
clusterSettings {
id '0'
maxId '2'
jGroups()
}
The code con gures a cluster node with ID=0, max ID=2, and the following default jGroups communication settings:
TCP address: 127.0.0.1
TCP port : 7800
Channel name: hybris-broadcast
Con guration le: jgroups-udp.xml
You can con gure the same cluster node, using a more verbose code:
clusterSettings {
id '0'
maxId '2'
jGroups {
defaultSettings()
}
}
You can also create the cluster node by specifying each setting individually:
clusterSettings {
id '0'
maxId '2'
jGroups {
tcpAddress '10.0.0.1'
tcpPort 6677
channelName 'my-custom-channel'
configFile '/Users/foo/my-custom-config.xml'
}
}
UDP Multicast Con guration
To con gure UDP multicast enabled-node, use the following code:
This is custom documentation. For more information, please visit the SAP Help Portal
168
5/27/2022
clusterSettings {
id '0'
maxId '2'
udpMulticast()
}
The code con gures a cluster node with ID=0, max ID=2, and the following default UDP multicast communication settings:
address: 224.0.0.0
port: 9997
You can con gure the cluster node, using a more verbose code:
clusterSettings {
id '0'
maxId '2'
udpMulticast {
standardSettings()
}
}
You can also create the cluster node by specifying each setting individually:
clusterSettings {
id '0'
maxId '2'
udpMulticast {
address '224.0.0.1'
port 9999
networkInterface 'en0'
debug true
}
}
UDP Unicast Con guration
To con gure UDP unicast-enabled node, use the following code:
clusterSettings {
id '0'
maxId '2'
udpUnicast {
address '10.0.0.55'
port 9999
clusterNodes '10.0.0.56:9999', '10.0.0.57:9999'
syncNodesInterval 1
debug true
}
}
Clustering
The Platform Plugin provides a simple way to set up local SAP Commerce clusters.
Overview
The following code excerpt shows how to set up local SAP Commerce clusters:
Setting Up Local hybris Clusters
cluster {
nodes 2
role hmc
portsStartingFrom 9001
messagingBasedOn jgroups()
dbSetup {
dbType 'mysql'
dbUrl 'jdbc:mysql://localhost/hybris?useConfigs=maxPerformance&characterEncoding=utf8'
This is custom documentation. For more information, please visit the SAP Help Portal
169
5/27/2022
dbUser 'root'
dbPassword ''
}
loadBalancer embeddedLoadBalancer {
host "localhost"
port 8001
nodeCookieName "cl_hmc_node_id"
stickySessionForCookie "JSESSIONID"
}
}.setup().initialize().startAllNodes()
The code example creates a cluster of two (2) Tomcats running on a local machine using the hmc role (see HybrisPlatformRole API). The cluster uses JGroups to
communicate between the nodes and connect all nodes to a single MySQL database. It starts an embedded load balancer with sticky sessions enabled. The database
initializes and all nodes get started.
When de ning roles to be used inside the cluster, de ne the database at the cluster level and not at the role level. The following code example shows you how to do it:
def hmc = platformRole {
roleName 'hmc'
localProperties {
property 'media.legacy.prettyURL', 'true'
}
extensions {
extensionNames 'hmc'
}
}
The installer ensures that all instances of the role within the cluster use the same database.
Specifying Role and Number of Instances
To specify the number of nodes in the cluster and role used, use the <nodes> and <role> parameters as shown in the following code example:
cluster {
nodes N
role theRole
...
}
In the example, the parameters are as follows:
<N> : An integer that indicates the number of nodes in the cluster. Note that node IDs are assigned automatically and incremented by 1 starting at 0.
<theRole>: The Commerce Platform role to be run by the nodes.
Specifying the Starting Port
To set the initial port for the local cluster, use the syntax portsStartingFrom. For example, to set the initial port in the cluster to 9001, use the following code:
Specifying starting ports
portsStartingFrom 9001
The installer automatically assigns the subsequent port numbers to instances, using ve (5) ports for each instance. For example, if a cluster is con gured with
portsStartingFrom 9001, the installer automatically assigns the subsequent ports as shown:
instance1:
http:
9001
ssl:
9002
ajp:
9003
jmx:
9004
jmxServer:
9005
instance2:
http:
9006
...
instance3:
This is custom documentation. For more information, please visit the SAP Help Portal
170
5/27/2022
http
9011
...
Specifying a Communication Mechanism
Use the messagingBasedOn syntax to specify the communication mechanism to be used by the cluster nodes, for example:
messagingBasedOn syntax
cluster {
...
messagingBasedOn jgroups()
...
}
Currently, the following options are supported:
jgroups(): Use JGroups with the following default values (the port number gets incremented for each instance, starting from port 7800):
jGroups {
tcpAddress '127.0.0.1'
tcpPort <port>
channelName 'hybris-broadcast'
configFile 'jgroups-udp.xml'
}
jgroups(String ip, int port, String channelName, String configFile): Custom JGroups con guration.
udpMulticast(String theNetworkInterface): UDP Multicast with the following default settings (and the provided networkInterface):
UDP Multicast with default settings
udpMulticast {
address '224.0.0.1'
port 9999
networkInterface theNetworkInterface
debug true
}
udpMulticast(final String ip, final int port, final String networkInterface, final boolean debug): Custom UDP Multicast
con guration.
Con guring Database Connections
To provide database connection parameters, use the dbSetup method. For more information, see the dbSetup Method in the HybrisPlatform API section.
Con guring the Media Storage Setup
To con gure media storage settings, use the mediaStorageSettings method. For more information, see the mediaStorageSettings Method in the HybrisPlatform
API section.
You can also set up local le media storage for all cluster nodes using the sysTempMediaStorage() method. It stores all media in the medias subfolder of the system
temp directory.
Setting Up a Load Balancer
To con gure a load balancer, use the <loadBalancer> parameter. By default, there is no load balance set up. To set up a load balancer, use EmbeddedLoadBalancer; it
starts a Java process that provides load balancing capabilities for testing and development. The following code excerpt shows an example used with the cluster:
Load Balancer
cluster {
//...
loadBalancer embeddedLoadBalancer {
host "localhost"
port 8001
nodeCookieName "cl_hmc_node_id"
stickySessionForCookie "JSESSIONID"
}
}
This is custom documentation. For more information, please visit the SAP Help Portal
171
5/27/2022
You can specify the following properties:
<host>: Host to use
<Port>: Port to use
<nodeCookieName>: The cookie name added by the load balancer to identify the nodes.
<stickySessionForCookie>: List of cookie names that be treated as sticky.
Operations on a Cluster
The following operations are permitted on clusters:
setup(): Con gures role and instances.
initialize(): Initializes the database assigned to the cluster using the con gured role.
startAllNodes(): Starts all cluster nodes in background mode.
startNodes(IntRange range): Starts the nodes from the speci ed range; for example: startNodes(1..2) starts the rst two nodes.
stopAllNodes(): Stops all cluster nodes in background mode.
stopnNodes(IntRange range): Stops the nodes within the speci ed range; for example: stopNodes(1..2) stops the rst two nodes.
Cluster Example
The following code provides an example of how to set up a cluster:
Setting up a Cluster
// Define role
def myRole = platformRole {
roleName 'persistencetest'
extensions {
extensionNames 'persistencetest'
}
}
// Prepare local hsql in server mode
hsqldb.port 49302
// define cluster
def myCluster = cluster {
nodes 3
role myRole
portsStartingFrom 9001
messagingBasedOn jgroups()
dbSetup hsqldb.createDb('myPlatform')
sysTempMediaStorage()
}
// Start hsqldb server
hsqldb.startInBackground()
// setup, initialize, and start a cluster
myCluster.setup().initialize().startAllNodes()
// stop cluster
myCluster().stopAllNodes()
// stop hsqldb server
hsqldb.stopInBackground()
Managing Tomcat
The Platform Plugin provides a simple API to manage Tomcat.
The following code excerpt shows how to deploy the DataHub Tomcat instance:
DataHub Tomcat Instance
def CATALINA_OPTS = "-Xms4096m -Xmx4096m ........ "
tomcat.instance('dataHub').setup {
ports {
This is custom documentation. For more information, please visit the SAP Help Portal
172
5/27/2022
http 9033
ssl
9034
}
webApps {
webApp 'datahub-webapp.war', file(suiteHome + '/hybris/bin/ext-integration/datahub/web-app/datahub-webapp-5.4.0.0-RC8.war')
}
libraries {
lib file("/Volumes/Data/projects/hybris_git/y/bin/platform/lib/dbdriver/mysql-connector-java-5.1.26.jar")
propertyFile "local.properties", {
property 'dataSource.driverClass', 'com.mysql.jdbc.Driver'
property 'dataSource.jdbcUrl', "jdbc:mysql://localhost/integration?useConfigs=maxPerformance"
property 'dataSource.username', 'root'
property 'dataSource.password', ''
}
}
}.start(CATALINA_OPTS)
The code example does the following:
Creates a directory named dataHub in the INSTALLER_HOME/work/ directory.
Creates the required Tomcat con guration les, such as con guring the ports, in the dataHub/conf directory.
Copies the speci ed war le to dataHub/webapps/datahub-webapp.war le.
Copies the MySQL driver from the speci ed absolute path to the dataHub/libs directory.
Creates the local.properties le, which contains the default properties, in the dataHub/lib directory.
Starts the Tomcat with the provided <CATALINA_OPTS>. All log les are stored in the dataHub/logs directory.
Description of the Deploy DataHub Code
Below you can nd detailed information about the Deploy DataHub Code.
Instance Name
Many Tomcat instances can be created and run using this API. To distinguish between the Tomcat instances, use the name of the instance as shown in the following example:
tomcat.instance('dataHub')
Each Tomcat instance must use a different port. If you have more than one Tomcat instance, make sure that the instances don't collide.
Tomcat Ports
The ports elements is used to specify which port a Tomcat instance is to use. The ports element has two parameters:
<http>
<ssl>
Web Applications
You can deploy multiple web applications on one Tomcat instance. Use thewebApps element to list the web applications. De ne each web application using the following
syntax:
Specifying web applications
webApp targetWarName, warFile
where:
<targetWarName> is a string that speci es the target le name of the web application in the tomcat/webapps directory.
<warFile> points to the war le. Note that you can compose the path to the le using variables exposed by the Platform Plugin, such as <suiteHome>.
Libraries
You use the libraries element to specify the content of the tomcat/lib folder. You can add les to the tomcat/lib folder using the following syntax:
tomcat/lib folder
This is custom documentation. For more information, please visit the SAP Help Portal
173
5/27/2022
lib file("/some/absolute/path/to/mysql-connector-java-5.1.26.jar")
You can also create property les in tomcat/lib using the following syntax:
propertyFile "local.properties", {
property 'key', 'value'
}
Starting and Stopping Tomcat
The Tomcat object has the following methods:
start(String tomcatOpts): Starts the Tomcat instance with the options provided.
stop: Stops the Tomcat instance.
Managing the HSQLDB
The HybrisHsqldb object provides methods to con gure the HSQLDB and run it as a standalone process. Unlike the SAP Commerce default database, the embedded
HSQLDB, which accepts only one connection, the HybrisHsqldb object accepts many connections. It can therefore be used in a cluster environment.
HSQLDB Port
By default, the HSQLDB runs on port 9009. You can use the optional port method to change default values, as follows:
hsqldb.port 49302
...
hsqldb.startInBackground()
 Note
This is an optional step. If you want to change the port on which the HSQLDB runs, you must do it before starting or stopping the database.
Con guring the Database
HSQLDB supports a maximum of nine (9) separate databases running on a single process. Use the <dbNames> property in the HybrisHsqldb object to con gure the
names of the databases as shown in the following example:
Con guring database names
hsqldb.dbNames = ['foo', 'bar']
...
hsqldb.startInBackground()
The following code shows how to con gure the HSQLDB to host two databases: foo and bar. The detailed con guration is displayed during startup.
Hsqldb successfully started:
foo
bar
jdbc:hsqldb:hsql://localhost:9009/foo
jdbc:hsqldb:hsql://localhost:9009/bar
 Note
Make sure to con gure the database before calling the startInBackground() method.
Con guring the Database Using the HybrisPlatform Object
You can con gure the HSQLDB using the HybrisPlatform API. You can use the createDb method to automatically con gure the database as a Platform object. The
following code shows how to do it:
Con guring Database using the HybrisPlatform Object
def hsqldbPlatform = platform {
dbSetup hsqldb.createDb("hybris")
// or simply
dbSetup hsqldb.createDb()
}
In the provided example:
This is custom documentation. For more information, please visit the SAP Help Portal
174
5/27/2022
createDb(): Adds new database named <db_N> (where <N> is a number of the currently created database) and returns the con guration for <dbSetup>
parameter.
Note that this throws a runtime exception when the database limit of nine (9) is exceeded.
createDb(String databaseName): Adds a new database with the speci ed name and returns the con guration for the <dbSetup> parameter.
 Note
Note that this throws a runtime exception when the database limit of nine (9) is exceeded or when a database with the speci ed name already exists.
Starting and Stopping The HSQLDB
The HSQLDB object has the following methods:
startInBackground: Starts an HSQLDB server instance on a con gured port.
stopInBackground: Stops a currently running HSQLDB server instance.
kill: Kills a currently running HSQLDB process and clears the database work directory.
 Note
Use the kill method cautiously because it kills processes abruptly and deletes all persisted and temporary data.
Detailed Information about Starting and Stopping the HSQLDB
During startup, the HSQLDB looks for a con guration le in its work directory. If a pid.txt le is present, the HSQLDB tries to connect to the URLs speci ed in the le and
has the possible results:
If successful, the HSQLDB assumes that the database was created previously; it stores some persistent data and becomes operational again.
If not successful: if the HSQLDB cannot connect, it assumes that the database was stopped in an unsafe way and may be corrupted. The HybrisHsqldb object will
try to kill the HSQLDBprocess that is currently running, clear the database work directory, and start the HSQLDB in a clean state.
Related Information
Installing SAP Commerce
Environment Variables
Internationalization and Localization
If you decide to start supporting multiple languages in your implementation of SAP Commerce, nd out about internationalization and localization (I18n). There are special
services available and special requirements for characters encoding in the localization les. There is also a mechanism that enables you to easily add new language to the
system.
For more information, see:
Character Encoding Requirements for Localization Files
Localization les support Unicode in order to display characters of almost all living languages.
Cockpit UI Element Localization
One of the step in the process of SAP Commerce localization is providing the localization of cockpit UI elements.
Internationalization and Localization Overview
Internationalization and localization are intended to adapt SAP Commerce to multiple languages and different requirements dependent on a region.
Localization Files Reference
SAP Commerce comes with a variety of localization les. Localization les hold source language texts or their localizations, for example used for display in the user
interface or within other system output.
Character Encoding Requirements for Localization Files
Localization les support Unicode in order to display characters of almost all living languages.
This leads to requirements concerning character encoding and le handling.
These requirements are relevant for everyone involved in preparing localization les before they are sent for translation and later reintegrated into SAP Commerce.
Localization les hold source language texts or their localizations, which in turn are used in user interfaces and other system outputs.
What Is a Byte Order Mark?
A byte order mark(BOM) is a sequence of bytes at the beginning of a le. For UTF-8 representation of the BOM this sequence looks like EFBBBF in hexadecimal notation. You
can nd it by opening the le with an hexadecimal editor like:
This is custom documentation. For more information, please visit the SAP Help Portal
175
5/27/2022
0xEd on the Mac OS X operating system
HexEdit on the Windows operating system
VIM with :%!xxd on the Linux operating system
This mark usually de nes which character encoding is being used and is quite common with Unicode les.
Character Encoding
Localization les use the following character sets:
Language
Character Encoding
Character Set
Special Character Handling
English
UTF-8
Unicode
Normal
All others
UTF-8
Unicode
Normal
 Note
Byte Order Mark
For proper encoding processing by translators and translation service providers, a BOM needs to be added to all text les before being sent out for translation. For more
information read the File Handling Before and After Translation section.
File Handling Before and After Translation
Localization les that are sent out for translation to translators or translation service providers, need to be modi ed in order to allow proper encoding. After getting the
localization les back, they need to be reintegrated.
Requirements for Localization Files to Be Sent Out
The following requirements must be ful lled before sending out localization les:
1. You need to add the UTF-8 BOM at the beginning of each le.
2. Convert Unicode to normal UTF-8 characters, for example U+006A j.
3. Correct encoding in UTF-8 representation.
If this is not done, the translation service provider might not be able to translate the les correctly or might not even be able to open them.
Requirements for Localization Files Before Reintegration
Before reintegrating, the following requirements must be ful lled for localization les:
1. There should be no BOMs at the beginning of the le. If there are any, you need to remove all UTF-8 BOMs.
2. Convert Unicode to normal UTF-8 characters. In this case it is easier to read these les.
3. Correct encoding in UTF-8.
If this is not done correctly, errors might occur while importing/building the Commerce Platform and it could cause character corruptions in the frontend/backend.
As you can see reintegration and sending out processes are quite similar to each other.
Related Information
Localization Files Reference
Cockpit UI Element Localization
One of the step in the process of SAP Commerce localization is providing the localization of cockpit UI elements.
To do that you need to add an element to UI XML le, and next put the localized string with the key into the properties le. It is an easy way to manage all the different
languages.
What Are the Cockpit UI Elements?
Cockpit UI Elements are elements like labels of the different sections. In the cockpits UI you can nd the Editor Area in the Organizer. For example, in the Product cockpit in
the Editor Area the main top rst label is Basic.
This is custom documentation. For more information, please visit the SAP Help Portal
176
5/27/2022
The most common UI elements of the cockpit are Advanced Search, List View, Editor, and Wizard.
Where to Find the UI XML Files
The XML les can be found in one of the following folders:
${HYBRIS_BIN_DIR} ${ext.@{extname}.path}/resources/@{extname}/import/config/
${HYBRIS_BIN_DIR} /platform/ext/@{extname}/resources/@{extname}
In these folders you can nd les which names are associated with the areas exisiting in the UI cockpits. For example, the expressions included in the XML lenames and
associated with the names of areas are AdvancedSearch, ListView, Editor and Wizard. The rest part of the XML lenames speci es also which part of the UI cocpkit
is concerned.
For instance, you can search for a product le associated with the Editor Area in the Product cockpit for the cockpit user. You can nd it in ${HYBRIS_BIN_DIR}
platform/ext/cockpit/resources/cockpit/import/config/ folder as an Editor_Product_CockpitUser.xml le.
Where to Find the Properties Files
In SAP Commerce there are properties les corresponding to the cockpit UI XML les.
The properties les can be found in one of the following folders:
${HYBRIS_BIN_DIR} ${ext.@{extname}.path}/resources/localization/
${HYBRIS_BIN_DIR} /platform/ext/@{extname}/resources/localization
This is custom documentation. For more information, please visit the SAP Help Portal
177
5/27/2022
The naming convention is i3-label_ languagetag .properties.
For more information, see Localization Files Reference.
 Note
The i3-label.properties does not have _en language tag in the lename.
Localization of the Cockpit UI Elements
The localization of the cockpit UI elements requires two substeps. Firstly, you need to provide correct label key in the UI XML le. In the second substep you need to translate
the string in the properties le. This string is assigned to the label key placed in the UI XML le.
While localizing the cockpit UI elements you need to add:
1. A <label key=" key.name "/> element to your UI XML le where you want your string to be placed later on.
2. The localized string with the key.name into the appropriate localization properties le accordingly: key.name = Key Value.
UI XML File
In the UI XML le insert <label key=" key.name " /> to add a key for your label that you can localize through a language speci c properties le later on.
In the following example the added label key is <label key="cockpit.con g.label.General" />.
Editor_Product_CockpitUser.xml
<editor>
<group qualifier="General" visible="true" initially-opened="true">
<label key="cockpit.config.label.General" />
<property qualifier="product.code" />
<property qualifier="product.name" />
<property qualifier="product.catalogversion" editor="shortListEditor"/>
<property qualifier="product.approvalStatus" />
<property qualifier="product.onlineDate" />
<property qualifier="product.offlineDate" />
<property qualifier="product.unit" />
<property qualifier="product.ean" />
<property qualifier="product.description" editor="wysiwyg"/>
</group>
<custom-group
class="de.hybris.platform.cockpit.services.config.impl.ClassAttrEditorSectionConfiguration"
qualifier="classification"
initially-opened="false"
show-if-empty="false">
<label key="config.general.attributes" />
</custom-group>
Properties File
To properly localize the properties le open it concerning the correct extension and language tag. Next, add the key and localized string to it.
You can nd the example of part of the localized properties le below. The rst line of the code shows how to assign the localized string in German with the correct label key
found in the UI XML le: cockpit.con g.label.General=Stammdaten. The UI XML le is the Editor_Product_CockpitUser.xml le shown in the UI XML File section.
i3-label_de.properties
cockpit.config.label.General=Stammdaten
cockpit.config.label.Additional=Erweitert
cockpit.config.label.Other=Andere
cockpit.config.label.All=Alle
config.general.actions=Aktionen
config.general.administration=Verwaltung
config.general.assigneduser=Zugewiesenen Benutzer
config.general.attributes=Attribute
config.general.bmecat=BMEcat
config.general.categorystructure=Kategoriestruktur
config.general.categorysystem=Kategoriesystem
config.general.comments=Kommentare
Related Information
Character Encoding Requirements for Localization Files
Localization Files Reference
Internationalization and Localization Overview
This is custom documentation. For more information, please visit the SAP Help Portal
178
5/27/2022
Internationalization and localization are intended to adapt SAP Commerce to multiple languages and different requirements dependent on a region.
The ServiceLayer contains the i18N package with services that provide internationalization and localization support for SAP Commerce. In particular it:
Allows developers to use Java I18N framework by providing SAP Commerce locale and timezone values, not necessarily the same as for Java Virtual Machine (JVM)
Provides access to CustomI18NService supporting Commerce Platform domain objects
Contains L10NService that returns localized resource bundles and values of localized attributes displayed in front-end applications.
Introduction to Internationalization and Localization
Internationalization in SAP Commerce is language- and country-speci c logic that is independent of the operating system. It is related to:
Java Platform objects like Locale, Currency, or TimeZone
SAP Commerce domain objects like LanguageModel, CurrencyModel or CountryModel
Localization in SAP Commerce is the logic used to fetch a locale speci c resource, that is String or ResourceBundle, which are used to present region speci c content to the
outside world.
Localization and Internationalization in SAP Commerce are not only limited to switching between different languages, but there are more aspects:
Language-speci c values: For every individual language, it is possible to specify a value for:
Type-system-related attributes
Classi cation attributes
Localization settings: For users in web front ends Language enables switching between different locale settings. The screen texts are displayed in different
localizations, depending on the language.
Limited range of available languages for user groups
Locale is a set of settings related to the language and region, in which a computer program executes.
Internationalization Features
Java provides a Locale object as a representation of a speci c geographical, political, or cultural region. For example, displaying a number is a locale-sensitive operation,
because the number should be formatted according to the conventions of the user's native country or region. When you create a custom Locale, no validity check is
performed. If you would like to check whether particular resources are available for the Locale you construct, you should query those resources. For example, ask the
NumberFormat for the locales it supports using its getAvailableLocales() method.
For more information, see http://download.oracle.com/javase/6/docs/api/index.html
: Java API documentation.
Java Objects vs. SAP Commerce Models
Java objects like Locale and Currency depend on Java Virtual Machine (JVM). The Commerce Platform does not contain one direct type corresponding to Java Locale.
However, it provides SAP Commerce speci c objects like LanguageModel, CountryModel, and RegionModel that may be used to create a speci c locale.
Currency Java object represents an existing currency de ned by ISO 4217 currency codes, whereas CurrencyModel can contain any currency con guration.
Java Locale can be transformed into LanguageModel. No validation is performed in this direction, so any existing Locale in the system can be stored as LanguageModel.
Getting a language for a default Locale can be done in the following way:
LanguageModel lanmodel = commonI18NService.getLanguage(Locale.getDefault().getLanguage());
If no LanguageModel exists for the given locale, the UnknownIdenti erException is thrown.
A similar situation exists for Java Currency representing an existing currency in a system, which can be transformed into CurrencyModel:
CurrencyModel cmodel = commonI18NService.getCurrency(javaCurrency.getCurrencyCode() );
cmodel.setSymbol(javaCurrency.getSymbol());
The transformation in the opposite direction is also possible. LanguageModel can be transformed into Locale:
LanguageModel lanModel ....
Locale someLocale = commonI18NService.getLocaleForLanguage(lanModel);
During a transformation of CurrencyModel into Java Currency a validation is performed on Java Virtual Machine level. It is checked if currencyCode is supported by ISO
4217. If not, Null is returned. You can get Currency instance for the CurrencyModel:
Currency someCurrency = i18nService.getBestMatchingCurrency(currencyModel.getIsocode());
To distinguish between different object types, the internationalization is split into two services: I18NService and CommonI18NService.
This is custom documentation. For more information, please visit the SAP Help Portal
179
5/27/2022
The I18NService operates only on Java classes. It is related to Platform speci c context, like tenant or session context, and their localization con guration, like language,
country, currency. What is more, it is able to in uence the Commerce Platform with that, for example by setting language for the current session. It also provides lists of plain
Java types, related to i18n, supported by the Commerce Platform, like all supported Currency or Locale objects. Moreover, it enables to verify if a certain type instance,
related to i18n, is supported by the Commerce Platform.
Sample code presenting how to get all supported Locales:
for(Locale locale : i18nService.getSupportedLocales())
{
LOG.info( "hybris Suit supports country "+ locale.getCountry());
}
The CommonI18NService operates on the Commerce Platform domain objects and is used only for fetching SAP Commerce Models for a current context of the usage. For
example, you may add new LanguageModel.
Localized Attributes
Localized attributes in SAP Commerce are attributes that can have different values for each language in the system. For example, the name of a unit might be different for
English and German, as shown in the following screenshot. Attributes are de ned to be localized by a speci c keyword in the attribute de nition in the extension_name -
items.xml le.
Attribute name
Localized
Identi er
No
Name
Yes
Conversion
No
Type
No
The idea of localized attributes is to store a map in Models containing a value for a speci c attribute for every locale supported by the Commerce Platform. As a result, you
can reach a proper value for a current localization settings. If there is no value for the current localization, the Language Fallback mechanism described below can be used.
If a type of Model that you are working on, you may directly set localized values for its attributes, for example for ProductModel:
//search for a product where the english name is "uniqueName_english" and the german name "uniqueName_deutsch".
ProductModel exampleProduct = modelService.create(ProductModel.class);
//do some localized intialization
exampleProduct.setName("some_deutsch_name", Locale.GERMAN);
exampleProduct.setName("some_english_name", Locale.ENGLISH);
....
//save the model
modelService.save(exampleProduct);
Language Fallback
This language fallback mechanism is responsible for providing a content for a localized attributes if no value is provided for the current localization settings. It can be
activated by setLocalizationFallbackEnabled method from I18NService. The example below shows how to create a fallback con guration and use it:
final LanguageModel firstLanguage = modelService.create(LanguageModel.class);
firstLanguage.setIsocode("first");
final LanguageModel secondLanguage = modelService.create(LanguageModel.class);
secondLanguage.setIsocode("second");
//set a fallback language
secondLanguage.setFallbackLanguages(Arrays.asList(firstLanguage));
modelService.saveAll();
final ProductModel product = modelService.create(ProductModel.class);
product.setCode("sampleProduct");
product.setCatalogVersion(version);
//set product description value in the first language
product.setDescription("some value in first ", new Locale(firstLanguage.getIsocode()));
//no value for the second language
modelService.saveAll();
//display product description in the first language
i18nService.setCurrentLocale(new Locale(firstLanguage.getIsocode()));
This is custom documentation. For more information, please visit the SAP Help Portal
180
5/27/2022
modelService.refresh(product);
System.out.println(product.getDescription());
//display product description in the second language
i18nService.setCurrentLocale(new Locale(secondLanguage.getIsocode()));
modelService.refresh(product);
System.out.println(product.getDescription());
The output result in this case is as follows:
some value in first
some value in first
If the fallback mechanism is disabled, the result is:
some value in first
null
Context Settings
Depending on settings related to the current session, like user currency, time zone or locale, logic applied for the internationalization is customized.
 Note
In order to pass a language or currency different from the current session settings, the logic should be called in a local session context, bound to the current thread. For
this you should pass an own SessionExecutionBody to sessionService.executeInLocalView, which provides a thread bound copy of current session context for the body
execution.
Users can have various restrictions, what results in different supported locals. It means that for different users, different sets of available languages can be available.
An example returning supported locales for admin user:
sessionService.executeInLocalView(new SessionExecutionBody()
{
public Object execute() {
sessionService.setAttribute("user",adminUserModel);
return i18nService.getSupportedLocales();
}
});
Current Locale settings can affect values returned for a localized attribute.
An example returning Chinese name for an Online catalog:
sessionService.executeInLocalView(new SessionExecutionBody()
{
public Object execute() {
i18nService.setCurrentLocale(chineseLocale);
CatalogModel cat = defaultCatalogService.getCatalog("Online");
return cat.getName();
}
});
Locale or Currency for the current session can also affect returning format objects like NumberFormat and DateFormat from FormatFactory.
An example presenting how to get a speci c currency format with a custom locale and currency:
sessionService.executeInLocalView(new SessionExecutionBody()
{
public Object execute() {
i18nService.setCurrentLocale(customLocale);
i18nService.setCurrentCurrency(customCurrency);
return formatFactory.createCurrencyFormat();
}
});
TimeZone settings can affect returning format objects like DateFormat and DateTimeFormat from FormatFactory.
An example presenting how to get a speci c DateFormat with custom locale and time zone:
sessionService.executeInLocalView(new SessionExecutionBody()
{
public Object execute() {
i18nService.setCurrentLocale(customLocale);
i18nService.setCurrentTimeZone(customTimeZone);
return formatFactory.createDateTimeFormat(DateFormat.FULL,-1);
}
});
Tenant context settings like locale and time zone, are used when the current session settings are not given. To provide a tenant-speci c locale and time zone, use the SAP
Commerce Administration Console:
This is custom documentation. For more information, please visit the SAP Help Portal
181
5/27/2022
If the session settings and tenant settings are given, the settings
from the JVM are used. For more information about tenants see Multi-Tenant Systems, Display List of Tenants section.
Internationalization and Localization provide also FormatFactory for getting formats with context dependent settings. Having a session speci c locale, currency and
timezone, SAP Commerce provides a range of standard methods to fetch number, currency and date formatters. When retrieving or creating item data, these methods
should be always preferred to standard Java formatter methods. Java methods use standard locale and time zone settings of the Virtual Machine if not explicitly speci ed.
Each session may use different locale or time zone. It may lead to incorrect presentation or even wrong data stored in a database, for example when parsing date elds
using the wrong time zone.
The FormatFactory provides the most common Format objects like:
NumberFormat for formatting currency, number, percent
DateFormat for date and time
 Note
Find Out More
createCurrencyFormat method gets the information from the current session. In order to create a format for other than current session settings, the logic should
be called in the local session context:
sessionService.executeInLocalView(new SessionExecutionBody()
{
public Object execute() {
i18nService.setCurrentLocale(customLocale);
i18nService.setCurrentCurrency(customCurrency);
return formatFactory.createCurrencyFormat();
}
});
The example below presents how to work with SimpleDateFormat and DecimalFormat:
SimpleDateFormat format = (SimpleDateFormat)factory.createDateTimeFormat(DateFormat.DEFAULT, -1);
format.applyPattern("yyyy-mm-dd");
DecimalFormat decimalFormat =(DecimalFormat) factory.createNumberFormat();
decimalFormat.applyPattern("some pattern");
Localization Features
To access the localized resource bundles, use L10NService. It covers the following functionality:
Accessing the resource bundles and related resources
Supporting SAP Commerce locale fallback mechanism
Provides localized values of types and their attributes in front-end applications
It does not provide a front-end speci c localization.
Type System Localization
Property les containing type system localization reside in /resources/localization directory in an extension. Every language in SAP Commerce can have individual
localizations and, by a consequence, individual property les.
Name of the localization properties le follows the pattern: extensionname -locales_ isocode .properties, where isocode is the identi er of a language in SAP
Commerce. For example: core-locales_en.properties or category-locales_de_at.properties.
Be aware that the delimiter between lename parts is the underscore (_). Depending on the application server, other delimiters like - or . may be ignored.
 Note
This is custom documentation. For more information, please visit the SAP Help Portal
182
5/27/2022
Renaming System Languages at Run Time Breaks Localizations
To allocate localization strings, SAP Commerce uses identi ers of languages, that is isocode attribute. You should make sure that the identi er of a language remains
constant. If the value of the isocode attribute is modi ed at run time and the system is updated, the allocation between localization le name and language isocode will
be broken. By consequence, localization strings will not be correctly assigned during system initialization or update. Names of localization property les should be
adapted accordingly.
The basic structure of a localization property le looks like this:
type.{typecode}.name=value
type.{typecode}.description=value
type.{typecode}.{attributedescriptor}.name=value
type.{typecode}.{attributedescriptor}.description=value
type.customerorderoverview.name=Order statistics
type.customerorderoverview.description=Statistic of order volume of each single customer
For example, the line type.tutorial.partofproduct.name=partOf Product navigates downwards through the type system hierarchy like this: ComposedType type ->subtype
tutorial ->attributedescriptor partofproduct ->localizedStringAttribute name and sets partOf Product value to the localizedString. It means that localizations for items and
their attributes are related to actual objects in the database. The following code snippet shows a sample of a locales_en le.
type.tutorial.longtext.name=Long text
type.tutorial.longtext.description=This element may contain text that is quite long.
type.tutorial.name=Name
type.tutorial.partofproduct.name=partOf Product
type.tutorial.picture.name=Picture
type.tutorial.picture.description=Via this picture, you may better visualize the product.
type.tutorial.short.name=Short
 Note
Update or Initialize after Changing Localization Files
After changes made in localization les, call ant in the extension directory. Afterwards, update or initialize SAP Commerce. Make sure that at least the Localize types
check box is selected in SAP Commerce Administration Console.
In uence of the Language Fallback
Language Fallback mechanism affects the localization in the following way:
Requesting the ResourceBundle returns some merged resource bundle for the current language and its fallback languages.
When requesting some speci c label value, the API looks for this property in the default ResourceBundle for the language as for all fallback languages, and returns
the rst not empty value for any of those bundles.
SAP Commerce provides a convenient way of de ning a list of fallback languages for each system language. If enabled, this feature replaces missing values of localized
attributes by possibly existing value for one of the speci ed fallback languages. For example, if de_DE has got de, en as fallback languages, a missing value for de_DE is
substituted by the one for de or, if also empty, by the one for en.
Unfortunately the standard way of localization using java.util.ResourceBundle cannot obey these fallback rules. Since it is completely based upon
java.util.Locale, the fallback mechanism for de_DE is always de, <vm startup language> regardless what has been speci ed within the SAP Commerce system.
This way you could end up with a confusing language fallback behavior. For example, storefront is currently showing data for the session language es, the fallback language
has been set to de, the Java VM has been started with en as system locale. Missing localized item attributes are substituted with existing de values as intended, but missing
resource bundle values are substituted by existing en values, because java.util.ResourceBundle will always fall back to the system locale as a last resort.
Accessing Localized Strings and Resource Bundle Using L10NService
Code snippet for fetching the bundle for a speci c locale:
i18nService.setCurrentLocale(Locale.ENGLISH);
ResourceBundle bundle = l10nService.getResourceBundle("servicelayer.test.testBundle");
String value = L10NService.getLocalizedString("some.key");
 Note
Fallback for names of attributes is disabled by default.
Related Information
Localization
Jalo-Based Locale and Timezone Handling
Languages and Localization
Internationalization (I18N) Support in the ServiceLayer
Internationalization (I18N) Support in the ServiceLayer
This is custom documentation. For more information, please visit the SAP Help Portal
183
5/27/2022
The ServiceLayer contains a service called I18NService that provides internationalization support for SAP Commerce.
 Note
As this document refers to Jalo, nd relevant information in Internationalization and Localization Overview.
In particular it:
Allows developers to use Java's rich I18N framework by providing SAP Commerce locale and timezone values (not necessarily the JVM locale and timezone)
Provides access to SAP Commerce own custom I18N support
Allows backwards compatibility to SAP Commerce earlier I18N framework.
Using Java's I18N Framework
To use Java's I18N framework, you need access to the application's current Locale. By default the Locale returned to the developer via
java.util.Local.defaultLocale is the JVM's own Locale which could well be different to the Locale being used by SAP Commerce.
Therefore, call the I18NService 's getCurrentLocale() method ( API Doc
) to retrieve the Locale currently being used by SAP Commerce. Similarly, you should call
I18NService 's getCurrentTimeZone() method to retrieve the SAP Commerce current timezone.
Subset of methods in I18NService.java:
//Get hybris' locale (and not JVM's locale), so you can use Java's standard I18N framework
Locale getCurrentLocale();
void setCurrentLocale(Locale loc);
// Get hybris' timezone (and not JVM's timezone), so you can use Java's standard I18N framework
TimeZone getCurrentTimeZone();
void setCurrentTimeZone(TimeZone loc);
With these in hand, you can make full use of Java's I18N API such as using MessageFormat, NumberFormat, DateFormat and Calendar. These methods allow us to
internationalise strings, dates and numbers, but they do not address localising SAP Commerce business objects themselves (such as Product, Catalog,
CatalogVersion). For that you need to look at SAP Commerce own I18N framework.
SAP Commerce I18N Framework
There are two areas of SAP Commerce I18N framework discussed below:
hybris' resourceBundle Framework
hybris' ServiceLayer Language Fallback
SAP Commerce resourceBundle Framework
SAP Commerce own I18N framework is based around a class named CompositeResourceBundle which is an extension of Java's java.util.ResourceBundle class.
Before describing SAP Commerce variant, let us consider the behavior of Java's own ResourceBundle below (see
http://java.sun.com/docs/books/tutorial/i18n/resbundle/prop le.html
for further discussion).In the SAP Commerce test suite, there are test property les for testing
and contrasting the ResourceBundle and CompositeResourceBundle logic:
testBundle_en_US.properties containing the text
action.testFallback1=US
testBundle_en.properties containing the text
action.testFallback1=En
action.testFallback2=En
testBundle_de.properties containing the text
action.testFallback1=De
action.testFallback2=De
action.testFallback3=De
Let us instantiate a ResourceBundle for these les, passing in the locale Locale.US:
final ResourceBundle javaBundle =
ResourceBundle.getBundle("testBundle", Locale.US, getClass().getClassLoader());
ResourceBundle Behavior
Here, you can expect the usual ResourceBundle behavior when using the javaBundle instance as detailed in the unit test code below:
//key available in testBundle_en_US.properties
assertEquals("US", javaBundle.getObject("action.testFallback1").toString());
//key not available in testBundle_en_US.properties but is available in testBundle_en.properties
assertEquals("En", javaBundle.getObject("action.testFallback2").toString());
This is custom documentation. For more information, please visit the SAP Help Portal
184
5/27/2022
try{
//key not available in testBundle_en_US.properties or testBundle_en.properties
javaBundle.getObject("action.testFallback3").toString();
fail("Should throw MissingResourceException");
}
catch (final MissingResourceException e){
}
This follows the usual resourceBundle logic when requesting a localized version of a string:
Look for the request key in the properties le testBundle_en_US.properties
If the key is not found, try the properties le testBundle_en.properties
If the key is not found, throw a MissingResourceException
CompositeResourceBundle Behavior
Let us now contrast that with how CompositeResourceBundle behaves. You can instantiate a CompositeResourceBundle as follows:
final ResourceBundle hybrisBundle = i18nService.getBundle("testBundle",
new Locale[] { Locale.US, Locale.GERMAN }, getClass().getClassLoader()
);
The second parameter consists of a list of Locales, which describe the fallback logic particular to CompositeResourceBundle. What this means is that the logic now
followed when accessing a string in the properties les becomes:
1. Look for the request key in le testBundle_en_US.properties
2. If the key is not found, try the le testBundle_en.properties.
3. If the key is not found, use the next Locale in your fallback list (in this case Locale.GERMAN) and therefore look in testBundle_de.properties
4. If the key is not found, throw a MissingResourceException.
This is illustrated in the following unit test code:
//key available in testBundle_en_US.properties
assertEquals("US", hybrisBundle.getObject("action.testFallback1").toString());
//key not available in testBundle_en_US.properties but is available in testBundle_en.properties
assertEquals("En", hybrisBundle.getObject("action.testFallback2").toString());
//key not available in testBundle_en_US.properties or testBundle_en.properties,
// but is available in testBundle_de.properties
assertEquals("De", hybrisBundle.getObject("action.testFallback3").toString());
try{
//key not available anywhere
hybrisBundle.getObject("action.testFallback4").toString();
fail("Should throw MissingResourceException");
}
catch (final MissingResourceException e){
}
You can see the complete unit test code in the method testCompositeResourceBundle2() in le I18NServiceTest.java.
SAP Commerce ServiceLayer Language Fallback
SAP Commerce provides a language fallback mechanism when using the ServiceLayer to query models for their localized names. The I18NService interface includes the
following method where you can enable or disable this feature:
void setLocalizationFallbackEnabled(boolean enabled);
To understand how this works, let us consider what happens if the LocalizationFallback feature is disabled.
Create a new language aNewLanguage and let us set its fallback language to the SAP Commerce default language. Your models will have no names that are localized to
aNewLanguage as you have just created it, but they will have names localized to SAP Commerce default language.
final Language defaultLanguage = jaloSession.getSessionContext().getLanguage(); // hybris default language
final Language aNewLanguage = C2LManager.getInstance().createLanguage( "aNewLanguage" ); // a new language
aNewLanguage.setFallbackLanguages( Collections.singletonList( defaultLanguage ));
// sets the new language's fallback to hybris default language
With the localization fallback feature disabled, if you now ask the model for its name localized to aNewLanguage you should see the value null returned because the model
aProductModel has no name that is localized to aNewLanguage.
i18nService.setLocalizationFallbackEnabled(false); // disable the fall back feature
assertNull(aProductModel.getName( aNewLanguage.getLocale() ) ); // query aProductModel for the localized name
Now let us enable the localization fallback feature:
i18nService.setLocalizationFallbackEnabled(true);
This is custom documentation. For more information, please visit the SAP Help Portal
185
5/27/2022
When you again query aProductModel for its name localized to aNewLanguage, you will receive the name that is localized to SAP Commerce default language, as the
framework has "fallen back" to aNewLanguage's fallback language, which in this case is SAP Commerce default language.
assertNotNull(aProductModel.getName(aNewLanguage.getLocale()));
assertEquals(aProductModel.getName(), product.getName(aNewLanguage.getLocale()));
You can see the complete unit test code in the method testLanguageFallback2() in le ItemModelTest.java.
Backward Compatibility to SAP Commerce Earlier Jalo-Based I18N Logic
Before the I18nService was introduced into the ServiceLayer, developers had been using models such as LanguageModel, CurrencyModel and CountryModel for their I18N
requirements. These are still supported, and can be accessed with the following methods in i18nservice.
Subset of methods in I18nService.java:
// For backwards compbatibility, provide access to the LanguageModel
LanguageModel getLanguage(String isocode);
Set getAllLanguages();
Set getAllActiveLanguages();
// For backwards compatibility, provide access to the CountryModel
CountryModel getCountry(String isocode);
Set getAllCountries();
// For backwards compbatibility, provide access to the CurrencyModel
CurrencyModel getCurrency(String isoCode);
Set getAllCurrencies();
CurrencyModel getBaseCurrency();
CurrencyModel getCurrentCurrency();
void setCurrentCurrency(CurrencyModel curr);
Jalo-Based Locale and Timezone Handling
The SAP Commerce Jalo layer is deprecated. Please refer to other localization topics to learn how to handle time zones.
 Caution
This page refers to deprecated software. For further details, see Deprecation Status.
One of the most common tasks in SAP Commerce application development is rendering numbers, monetary amounts and timestamps. Commerce Platform can run in multitenant mode, where tenant-speci c locale and timezone handling is useful. Without this support, each web application would have to determine which locale and timezone
would be appropriate for the current tenant, and create its own number, currency and date formatters.
Session Provides Locale and Timezone
Each JaloSession carries a Locale and TimeZone directly inside the SessionContext. This way you can change it manually if required without affecting the session
language item. Determining the locale upon session creation works as follows:
1. Determine the session language.
If the user provides a language, use it.
If not, try to nd language matching the (new) tenant default locale.
Otherwise, fall back to the rst active language.
2. Try to get the locale from the language.
3. If that fails, then use the tenant-speci c locale.
4. If no tenant-speci c locale is set, use the Java VM default locale.
The current tenant may also specify a default timezone. This default is used as a session timezone upon session creation. If no tenant-speci c timezone has been set, then
the Commerce Platform default is used. By holding a locale and timezone for each session, you can avoid having to implement your own locale and timezone guessing logic in
the business logic. The session is an always present session container for you to fetch the locale and timezone from.
However, the most important reason for holding locale and timezone in the session is that Commerce Platform contains a number of dedicated methods in the Utilities
class that provide number, currency and date formatter instances according to the current session settings.
Tenant Speci c Locale and Timezone
Each slave tenant can specify a custom locale and timezone when it is created. If nothing is speci ed, then the tenant uses the Java VM default settings for locale and
timezone. This way multiple tenants may be hosted together using their locale and timezone settings even if they're sharing web applications such as HMC.
Affected Modules
This feature affects many SAP Commerce modules.
HMC
This is custom documentation. For more information, please visit the SAP Help Portal
186
5/27/2022
Assume you have one German tenant with de_DE as the locale, and GMT+1 as the time zone. You also have an English tenant using en and GMT. If a German employee logs
into the HMC, they will see all numbers rendered as speci ed by the Germany locale and all date and time elds according to the GMT+1 zone. The English user will see
English number styles and date and time elds according to the GMT zone.
If the German user saves 01.01.2007 12:00:00 as the timestamp, and their English counterpart types 01.01.2007 11:00:00 they're actually writing the same timestamp to the
database.
ImpEx Import and Export
The default locale is always the locale of the current tenant.
Please keep in mind that ImpEx les working well for one tenant may break for another unless the locale is set explicitely inside the le as shown in the following example.
#% impex.setLocale( java.util.Locale.GERMANY );
INSERT Product; ... ; europe1Prices[translator=...]
; ... ; 12,50 EUR
#% impex.setLocale( java.util.Locale.EN );
INSERT Product; ... ; offlineDate ; europe1Prices[translator=...]
; ... ; 12.50 EUR
This works best when the CSV le is not used as an ImpEx le, but included within a separate ImpEx script.
Standard Methods for Getting Number, Currency and Date Formatters
SAP Commerce provides a range of standard methods to fetch number, currency and date formatters in the class de.hybris.platform.util.Utilities.
When reading or writing item data these methods should be always be preferred to standard Java formatter methods because Java methods will use the VM standard locale
and timezone settings wherever not speci ed explicitly. As each session may use a different locale or timezone, this may lead to the wrong presentation or even the wrong
data written to the database. when parsing date elds using the wrong timezone, for example.
Shortcut for getting the locale from current session
method
returns
prefer to
getDefaultLocale()
Locale
Locale.getDefault()
Creates a several number format instances using the session locale
method
returns
prefer to
getNumberInstance()
NumberFormat
NumberFormat.getNumberInstance()
getIntegerInstance()
NumberFormat
NumberFormat.getIntegerInstance()
getPercentInstance()
NumberFormat
NumberFormat.getPercentInstance()
Creates a decimal format from pattern using the session locale
method
returns
prefer to
getDecimalFormat(String)
DecimalFormat
new DecimalFormat(String)
Creates currency number format instances using the session locale and (session) currency;
The returned number format will be initialized with the currency sign and digits from the currency item - the java vm defaults are overwritten here.
method
returns
prefer to
getCurrencyInstance()
NumberFormat
NumberFormat.getCurrencyInstance()
getCurrencyInstance(Currency)
NumberFormat
Creates calendar instances using the session timezone and (session) locale
method
returns
prefer to
getDefaultCalendar()
Calendar
Calendar.getInstance()
getDefaultCalendar(Locale)
Calendar
Calendar.getInstance(Locale)
This is custom documentation. For more information, please visit the SAP Help Portal
187
5/27/2022
Creates SimpleDateFormat instances from pattern using the (session) locale and calendar (see above)
method
returns
prefer to
getSimpleDateFormat(String)
SimpleDateFormat
new SimpleDateFormat(String)
getSimpleDateFormat(String,Locale)
SimpleDateFormat
new SimpleDateFormat(String)
Creates date (-time) format instances using the session timezone, (session) locale and optionally speci ed style ags
method
returns
prefer to
getDateTimeInstance()
DateFormat
DateFormat.getDateTimeInstance()
getDateTimeInstance(int,int)
DateFormat
DateFormat.getDateTimeInstance(int,int)
getDateTimeInstance(int,int,Locale)
DateFormat
DateFormat.getDateTimeInstance(int,int,Locale)
getDateInstance()
DateFormat
DateFormat.getDateInstance()
getDateInstance(int,Locale)
DateFormat
DateFormat.getDateInstance(int,Locale)
Language Fallback Rules versus Resource Bundles
SAP Commerce provides a convenient way of de ning a list of fallback languages for each system language. If enabled this feature replaces missing localized attribute values
with an existing value for one of the speci ed fallback languages. For example, if de_DE has got [ de, en ] as fallback languages, a missing value for de_DE would be
substituted by the one for de or, if also empty, by the one for en. Unfortunately the standard way of localization via java.util.ResourceBundle cannot obey these
fallback rules. Since it is completely based upon java.uil.Locale the fallback mechanism for de_DE is always [ de, <vm startup language> ] no matter what has been
speci ed within the SAP Commerce system.
This way you could end up with confusing language fallback behavior like this: a storefront is currently showing data for the session language es; the fallback language has
been set to de; the java vm has been started with en as system locale; now missing localized item attributes are substituted with existing de values (as intented) but
missing resource bundle values are substitued by existing en values because java.util.ResourceBundle will always fall back to the system locale as a last resort.
Standard Methods for Obtaining Resource Bundles
SAP Commerce offers de.hybris.platform.util.Utilities methods for obtaining a resource bundle which does obey the SAP Commerce language fallback rules
and the tenant speci c default locale.
method
prefer to
remarks
getResourceBundle(String)
ResourceBundle.getBundle(String)
resource bundle for current session language/locale; to be
used inside a SAP Commerce extension class loader
getResourceBundle(String,ClassLoader)
ResourceBundle.getBundle( String )
resource bundle for current session language/locale; to be
used if resource data is provided by a different class loader
e.g. webapp class loader
getResourceBundle(SessionContext,String)
ResourceBundle.getBundle( String,Locale )
resource bundle for speci ed session language/locale; to be
used inside a SAP Commerce extension class loader
getResourceBundle( SessionContext, String,
ClassLoader )
ResourceBundle.getBundle( String, Locale,
ClassLoader )
resource bundle for speci ed session language/locale; to be
used if resource data is provided by a different class loader
e.g. webapp class loader
getResourceBundle( Language, String )
ResourceBundle.getBundle( String, Locale )
resource bundle for speci ed session language/locale; to be
used inside a SAP Commerce extension class loader
getResourceBundle( Language, String,
ClassLoader )
ResourceBundle.getBundle( String, Locale,
ClassLoader )
resource bundle for speci ed session language/locale; to be
used if resource data is provided by a different class loader
e.g. webapp class loader
getResourceBundle( Locale[], String,
ClassLoader )
ResourceBundle.getBundle( String, Locale,
ClassLoader )
resource bundle for a custom fallback list of locales
Languages and Localization
SAP Commerce has built-in support for multiple languages. Thus, it is possible to easily use SAP Commerce to run applications for different countries.
 Note
As this document refers to Jalo, nd relevant information in Internationalization and Localization Overview.
What Is a Language in SAP Commerce?
A Language in the context of SAP Commerce is not only limited to actually switching between, say, English, German, and French, but there are more aspects:
Language-speci c values
This is custom documentation. For more information, please visit the SAP Help Portal
188
5/27/2022
For every individual language, it is possible to specify a speci c value for
type-system-related attributes
classi cation attributes
Localization Setting
For users in the HMC and a web frontend, a Language is a means of switching between different locale settings. The screen texts will be displayed in different
localizations, depending on the language.
Synchronization of catalog versions
Allowed values for classi cation systems
limited range of available languages for user groups
You may create any number of languages in SAP Commerce.
 Note
Be aware of localization strings and localized attributes in the HMC and web frontends. Texts conveying the same message can be different in length across different
languages. For example, texts in German tend to be longer than texts in English. By consequence, a xed-size screen layout may t for English, but end up broken for
German.
The effect of different text length applies to both the actual localization strings and the localized attribute values.
Languages available out-of-the-box in Backoffice include:
en: English
de: German
fr: French
it: Italian
es: Spanish (Spain)
es_CO: Latin-American Spanish
ja: Japanese
ko: Korean
pt: Brazilian Portuguese
ru: Russian
zh: Simpli ed Chinese
zh_TW: Traditional Chinese
hi: Hindi
id: Bahasa (Indonesia)
Localization
Basically, we need to make a difference between the actual localization mechanism on the one hand (which allows displaying language-speci c attribute names, screen texts,
and so on) and localized attributes on the other hand.
Localizations are displayed texts that are different for every individual language. This does not have anything to do with language-speci c values.
This is caused by the technical way of how SAP Commerce handles attributes. An attribute is technically represented by an AttributeDescriptor, which can have an individual
name per system language, and holds values.
AttributeDescriptors for non-localized attributes can have a localized name and one individual value over all system languages. The name is set by the localization
mechanism during type system generation, whereas the values are set by runtime (via an HMC user, for example).
AttributeDescriptors for localized attributes can have a localized name and one individual value per system language. The name is set by the localization mechanism
during type system generation, whereas the values are set by runtime (via an HMC user, for example).
In the following diagram, the Product type has two attributes: the non-localized attribute code and the localized attribute description.
This is custom documentation. For more information, please visit the SAP Help Portal
189
5/27/2022
Attribute
Attribute value for DE
Attribute value for EN
Attribute value for FR
Product1:code
(Product1)
(Product1)
(Product1)
Product2:code
(Product2)
(Product2)
(Product2)
Product1:description
Beschreibung
Description
Légende
Product2:description
MeineBeschreibung
MyDescription
MaLégende
For an in-depth discussion of the localization mechanism and how to set localization strings, please refer to the documentation on localization.
Localized Attributes
Localized attributes in SAP Commerce are attributes that can have different values for each language in the system. For example, the name of a unit might be different for
English, German, and French, as shown in the following screenshot. Attributes are de ned to be localized via a speci c key word in the attribute de nition in the items.xml
le items.xml.
Attribute name
Localized?
Identi er
no
Name
yes
Conversion
no
Where Do Languages Have Effect?
Languages in SAP Commerce take effect mostly in relation to user management, session management, and catalog access rights.
Even though related logically, from a technical point of view most of the currency and ordering-related concepts in SAP Commerce do not have a connection to languages by
factory default.
Regions, countries, currencies, and addresses do not have a direct connection to languages. In other words: even if you only have English as a system language, your
customers will still be able to order in EUR, USD, JPY, and set up addresses in Germany, France, and China. If you want to ensure that only inhabitants of certain countries will
be able to use certain currencies or languages, you will need to implement the restricition explicitly.
Default Language for a User
A user (whether Customer or Employee) may select a default language optionally. If the user logs into SAP Commerce, the selected default language will be used until the
user manually sets another language.
If a user does not select a default language explicitly, SAP Commerce uses the system default language. Which language is used by system default depends on the tenant
and locale settings.
On a more technical level, the language is set to the SessionContext of the JaloSession used. The default language of a user account is set to the SessionContext of the
JaloSession when the JaloSession is created, and will remain the active language until changed explicitly.
The basic mechanism of setting the language to the SessionContext:
Language de = C2LManager.getInstance().getLanguageByIsoCode( "de" );
JaloSession.getCurrentSession().getSessionContext().setLanguage( de );
This is custom documentation. For more information, please visit the SAP Help Portal
190
5/27/2022
The basic mechanism of retrieving the language from the SessionContext:
Language currLang = JaloSession.getCurrentSession().getSessionContext().getLanguage();
Allowed Languages for a Catalog Version
For each catalog version, SAP Commerce allows specifying an individual range of languages. Languages set for a catalog version affect:
the localization range of attributes displayed in the HMC
On a catalog version and its related objects (categories, products, etc), SAP Commerce displays localized values only in those languages set for the catalog version. If
no languages are speci ed explicitly, then localized values in all languages will be displayed.
For example, if the system languages are en, de, and fr, and only de is set for a catalog version, then only the attribute values in German will be visible on
categories and products which are part of the catalog version.
For example, if the system languages are en, de, and fr, and no language is set for a catalog version, then the attribute values in English, German and French
will be visible on categories and products which are part of the catalog version.
the localization range of attributes used when synchronizing between catalog versions
Synchronization only affects
non-localized attributes and
the localized values of the languages set for the catalog version.
Localization in the HMC
The Hybris Management Console allows each individual user to select a choice of languages which will be displayed in the upper right-hand side drop-down menu. Please
refer to the hMC - End User Guide.
Classi cation
Like type system-based attributes, Classi cation -based attributes can also be localized as to the attribute name and value.
The following screenshots show the Hybris Management Console representation of the localized Classi cation attribute Dimensions.
Type classi cation attribute collapsed
Type classi cation attribute expanded
To mark a classi cation attribute as localized,
open the Category Feature for the classi cation attribute in the Hybris Management Console and
check the Multilanguage modi er:
User Groups
The Hybris Management Console allows editing values in all the system languages available.
A user group allows limiting the available range of languages for its members. The members of the user group will not have all the potential values in all system languages
available, but only those that are enabled by the user group.
 Note
This is custom documentation. For more information, please visit the SAP Help Portal
191
5/27/2022
This mechanism does not limit the number of languages from which a user can choose the HMC interface. The language selection drop-down menu on the upper righthand side always displays the full range of languages available in the system. The drop-down menu is to allow users to select the HMC interface language, not to limit the
range of languages in which values can be edited by the user.
Fallback Languages
A fallback is something you use if the original idea does not work out. In the case of fallback languages in SAP Commerce, a fallback language is a language that is used if the
"original" language has no value set for a certain localization.
Basically, a fallback languages relies by and large on the localizations of at least one other language and overrides the other language's localizations in selected cases.
Fallback languages are useful within a family of languages where many localizations are the same for several languages, but some individual localizations differ. A common
application for fallback languages is the German family of languages, where German, Swiss German and Austrian use by and large the same vocabulary and grammar except for individual differences.
The following screenshot gives an example on this: the language DE_CH has de set as fallback language. By consequence, SAP Commerce uses the localizations of de
wherever DE_CH has no localization.
When SAP Commerce looks up a localization, the mechanism iterates over fallback languages in the speci ed order until a localization is found. The rst localization that is
found in the process is returned. After a localization has been found, the iteration ends.
In addition, fallback hierarchies are not resolved. This is because for every single localization, the entire hierarchy of fallback languages would have to be searched, which
would result in bad performance.
For example, in the following screenshot the Language DE_CH has the fallback languages it, fr, and de. This means that during localization lookup, a localization is rst
searched in the Language it, after that, in fr, and, if still no localization has been found, in de. If de contains no localization, then the attribute is considered unlocalized. If de
contains no localization but has a fallback language, that fallback language would not be checked for localization and the attribute would still be considered unlocalized.
This is custom documentation. For more information, please visit the SAP Help Portal
192
5/27/2022
Unlocalized attributes are displayed with square brackets ([ and ], respectively) around their name, as shown in the following screenshot:
Fallback languages also apply to localized error messages in the Hybris Management Console.
Countries and Regions
A Country in SAP Commerce forms an optional part of an Address and can hold any number of Regions.
A Country is an optional part of an Address. Addresses can be used without specifying a country.
This is custom documentation. For more information, please visit the SAP Help Portal
193
5/27/2022
A Country can optionally be part of a delivery zone.
Languages are not logically related to Countries, and neither are Countries logically related to Languages. By consequence, the range of languages a user can choose from is
not affected by the country they could be living in. In other words, a user does not need to have an address located in an English-speaking country to be able to use the
English language.
Please also refer to the discussion of Addresses in the Ordering Process documentation.
A Region is an optional part of an Address. An Address can optionally hold one single Region, but a Region can be used by any number of Addresses.
Regions may be necessary for cases when you have to sub-divide a country into different individual entities (such as federal states, for example). For example, the individual
federal states of the United States of America have individual tax jurisdictions. When calculating tax values for an order, you could use the region of the delivery address to
determine the actual tax jurisdiction.
Code Snippets for Using Languages
Basically, a localized attribute has two kinds of generated getter and setter methods respectively. For both getter and setter methods, there is one method that gets (or
sets, respectively) all values for all languages via a Java Map, and one method that gets (or sets, respectively) the value for the currently active language only.
For example, for the localized String attribute MyAttribute, there will be these generated getter and setter methods:
Getter methods:
Language-speci c
Gets the value for the attribute for the language which is currently set for the active JaloSession. For example, if the JaloSession's language is set to en,
calling the getter method will result in getting the attribute value for English, and for English only.
Product prod = ...
String name = prod.getName();
public String getMyAttribute( nal SessionContext ctx)
public String getMyAttribute()
Generic
The basic mechanism can be seen from the method parameters: you receive a Map whose key is the language for which to get the value, and whose value is
the actual localized value.
Map<String, Object> params = new HashMap<String, Object>();
params.put( WorkflowAction.NAME, getAllName() );
public Map<Language,String> getAllMyAttribute( nal SessionContext ctx)
public Map<Language,String> getAllMyAttribute()
Setter methods:
Language-speci c
Sets the value for the attribute for the language which is currently set for the active JaloSession. For example, if the JaloSession's language is set to en, calling
the setter method will result in the attribute value for English to be set, and for English only.
Product p1 = ProductManager.getInstance().createProduct("p1");
p1.setDescription("description without html");
public void setMyAttribute( nal SessionContext ctx, nal String value)
public void setMyAttribute( nal String value)
Generic
The basic mechanism can be seen from the method parameters: you pass a Map whose key is the language for which to set the value, and whose value is the
actual localized value.
Map names = new HashMap();
names.put( de, "beschreibung_de" );
names.put( en, "description_en" );
names.put( fr, "légende_fr" );
Product p = ...
p.setAllDescriptions( names );
public void setAllMyAttribute( nal SessionContext ctx, nal Map<Language,String> value)
public void setAllMyAttribute( nal Map<Language,String> value)
ImpEx
When setting localized attribute values, you may
specify the language explicitly for which the value is to be set (recommended)
This is custom documentation. For more information, please visit the SAP Help Portal
194
5/27/2022
Sets the value for the attribute for the speci ed language.
INSERT_UPDATE Category;code[unique=true];name[lang=de];name[lang=en]
;CL1100; Jeans; Jeanshosen; jeans
omit a language speci cation (discouraged)
In this case, the value for the attribute is set for the language which is selected for the current JaloSession. If you can be sure which language will be active for the
current JaloSession, then this approach is possible. However, SAP recommends specifying explicitly a language so that you can be sure which language's value will be
set.
INSERT_UPDATE Category;code[unique=true];name
;CL1100; Jeans; Jeanshosen
C2LManager
The Manager class for creation and removal of localization-related SAP Commerce items is the C2LManager (de.hybris.platform.jalo.c2l package). For a list of available
methods, please refer to the SAP Commerce JavaDocs.
For example:
Set<Language> allLangs = C2LManager.getInstance().getAllLanguages();
Related Information
Internationalization and Localization Overview
Localization
There are two kinds of localization for extensions: one for the Hybris Management Console (HMC) and one for the type system. Unlike types, HMC elements do not
necessarily have concrete instances in the database and may be there just for display, for example sections and tabs.
 Note
As this document refers to Jalo, nd relevant information in Internationalization and Localization Overview.
Type System Localization
The type system localization les are property les and reside in an extension's /resources/localization subdirectory. Every in SAP Commerce can have individual
localizations and, by consequence, have individual property les.
For more information about property les, see http://en.wikipedia.org/wiki/.properties
. For more information about languages, see Languages and Localization.
The localization properties le's name follows the pattern ${extensionname}-locales_${isocode}.properties (such as core-locales_en.properties or
category-locales_de_at.properties), where:
${extensionname} is the name of the extension
${isocode} is the identi er of a language in SAP Commerce.
Be aware that the delimiter between lename parts is the underscore ( _ ). Depending on the application server, other delimiters (for example - , or .) may be ignored.
 Note
Renaming system languages by runtime will break localizations
SAP Commerce uses the identi er of languages (isocode attribute) to allocate localization strings, you will need to make sure that the identi er of a language remains
constant. If you modify the value of the isocode attribute of a language by runtime and re-update the system, you will break the allocation between localization le
name and language isocode. By consequence, localization strings will not be correctly assigned during system initialization or update.
In essence, if you rename languages without adapting the lenames of localization property les, you will end up with incorrectly assigned localization strings - or with no
localization strings at all.
The Basic Structure of a Localization Property File
The basic structure of a localization property le looks like this:
type.{typecode}.name=value
type.{typecode}.description=value
type.{typecode}.{attributedescriptor}.name=value
type.{typecode}.{attributedescriptor}.description=value
type.customerorderoverview.name=Order statistics
type.customerorderoverview.description=Statistic of order volume of each single customer
The line type.tutorial.partofproduct.name=partOf Product will navigate downwards through the type system hierarchy like this: ComposedType type ->
subtype tutorial -> attributedescriptor partofproduct -> localizedStringAttribute name and set this localizedString to the value partOf
This is custom documentation. For more information, please visit the SAP Help Portal
195
5/27/2022
Product. This means that localizations for Platform items and those items' attributes relate to actual objects in the database. The following code snippet shows you a
sample of an locales_en le.
type.tutorial.longtext.name=Long text
type.tutorial.longtext.description=This element may contain text that is quite long.
type.tutorial.name=Name
type.tutorial.partofproduct.name=partOf Product
type.tutorial.picture.name=Picture
type.tutorial.picture.description=Via this picture, you may better visualize the product.
type.tutorial.short.name=Short
After you made changes to the localization les, call ant in the extension directory. Also, you need to update (or initialize) SAP Commerce for the changes to take effect.
Using the HMC Localization Export Function to Create Type System Localization Files
Creating a localization le with all the localization strings for types and their attributes manually is rather inconvenient, there is an alternative way.
The HMC allows creating localization les for types and attributes de ned within an extension automatically.
1. Log into the HMC using an administrative account.
2. Navigate to System Tools Type System Export .
3. Check the extension(s) for which you want the localization strings to be exported.
4. Click the Export type localizations button.
A pop-up window will open containing the localization strings.
You can now copy and paste these localization strings into your localization les.
 Note
Exports extension-based type and attribute localization strings only
As the localization export function of the HMC works extension-based and does not completely resolve attribute references, you will only get localization strings for
attributes de ned in the checked extensions. Localization strings for attributes speci ed in an extension other than the checked ones will not be exported.
For example, if your extension MyExtension extends the Product type by MyAttribute and you export the type system localization for MyExtension, you will only
get the localization strings for MyAttribute, not for all attributes of Product.
Conversely, if you export the core extension (in which the type Product is de ned), you will not get localization strings for MyAttribute.
Hybris Management Console Localization
 Note
Renaming system languages will break localizations
SAP Commerce uses the identi er of languages (isocode attribute) to allocate localization strings, you will need to make sure that the identi er of a language remains
constant. If you modify the value of the isocode attribute of a language, you will break the allocation between localization string and language. By consequence,
localization strings will not be correctly assigned during system initialization or update.
In essence, if you rename languages without adapting the lenames of localization property les, you will end up with incorrectly assigned localization strings - or with no
localization strings at all.
This is custom documentation. For more information, please visit the SAP Help Portal
196
5/27/2022
The Hybris Management Console localization les are also named locales_${isocode}.properties, but they are located in the hmc/resources/${package}
subdirectory (hmc/resources/de/hybris/platform/voucher, for example).
The entries in these les are similar to those in the type system localization les. However, they do not refer to actual SAP Commerce items. Items and attributes are made
persistent by their type de nition, and their values are stored in the database. The HMC-speci c localizations do not relate to types nor any persistent objects, however. As
there is no type de nition, there also is no inheritance and, thus, no naming pattern. That means that you can assign any identi er to HMC-speci c localizations, unlike items
localizations that apply to actual objects.
The following code snippet was taken from a HMC-speci c localization le and slightly adapted.
section.abstractorder.vouchers
section.restriction.errormessage
section.restrictions
section.voucher.description
section.voucher.generated.codes
section.voucher.orders
section.voucher.restrictions
section.voucher.value
=
=
=
=
=
=
=
=
Vouchers
Error message
Restrictions
Description
Generated voucher codes
This voucher is applied to the following orders
Restrictions for redemption
Voucher value
tab.voucher.orders
= Orders
tab.voucher.restrictions = Restrictions
error.voucher.already.applied
error.voucher.invalid.vouchercode
error.voucher.not.found
error.voucher.redeem.unknown
error.voucher.vouchercode.already.used
=
=
=
=
=
The voucher is already applied and cannot be applied again.
The entered voucher code is not valid.
Could not find appropriate voucher.
The voucher could not be redeemed because of an unknown error.
The voucher code is already redeemed.
With that mechanism it is possible that two extensions are declaring the same localization key (intended for overwriting purposes or unintended by using same key). As
result only one speci cation wins and is used. The processing iterates over all extensions with hmc module starting with the hmc extension itself and uses the last found key.
The iterating order can be reproduced by looking at the hmcextensions.xml le.
A second aspect of HMC-speci c localizations is that they can contain parameters that are replaced with the actual value at runtime. Parameters are included into the
localization de nition at the designated location via {x}, where x indicates the consecutive number of the parameter. The following two code snippets illustrate how to use
parameter de nitions. The rst snippet is an extract from a localization le, while the second snippet is a call for a localized string. To display a localized string with
parameters, you call the static Java method MessageFormat.format( String pattern, Object[] arguments) , where String pattern is the localized String
and Object[] arguments is an array of objects that will be used for the parameters in the localization string in the passed order.
exception.publicationeditor.unabletodelete = Unable to delete item {0} ({1}): {2}
try
{
removeItem( selectedItem );
}
catch( ConsistencyCheckException e )
{
errors.add(
MessageFormat.format(
getLocalizedString( "exception.publicationeditor.unabletodelete" ),
new Object[]{
getItemName( selectedItem ),
// {0}
selectedItem.getComposedType().getName(),
// {1}
e.getLocalizedMessage()
// {2}
}
)
);
e.printStackTrace();
}
The resulting error message will look like this:
Unable to delete item X004 (Sweatshirts): item is already deleted.
Using Other Localized Strings
Optionally, SAP Commerce also allows using the localization mechanism for localization strings that are neither for the Type System nor for the Hybris Management
Console, such as for the web shop or for a custom Cockpit implementation.
To use such localization strings:
1. Add the localization values to the type system localization les of your extension, located in the /resources/localization subdirectory, such as:
my.localized.key=my localized value
2. Retrieve the localized value in your code by calling
String localizedString = de.hybris.platform.util.localization.Localization.getLocalizedString("my.localized.key");
Related Information
Internationalization and Localization Overview
This is custom documentation. For more information, please visit the SAP Help Portal
197
5/27/2022
Localization Files Reference
SAP Commerce comes with a variety of localization les. Localization les hold source language texts or their localizations, for example used for display in the user interface
or within other system output.
Language Code in the Filename
The language code in le names is indicated by a language tag: _languagetag. extension.
The language tag follows language code pattern ISO 639-1 for all les to be translated, for example:
_en.properties
_en.zul
_de.properties
_fr.properties
_ja.properties
_zh.properties
_it.properties
_pt.properties
 Note
There are English source les which do not have _en language tag such as:
BasecommerceMessages.properties
i3-label.properties
If multiple variants of a language are to be offered, for example German for Germany and German for Switzerland, the following standard is applied _languagetag _
countrytag.extension.
For examples:
_de_DE.properties
_de_CH.properties
_pt_BR.properties
Localization Files
Localization les sent out for translation or translations received from the translation service providers need to be modi ed in order to have proper encoding. Before
sending localization les out or reintegrating them, you need to prepare them. You can read about the requirements for localization les in Character Encoding
Requirements for Localization Files.
In the next sections there are tables which indicate how to nd the expressions which are to be searched for and then translated.
In the Filename pattern row there are lenames which you need to search for. These les include the expressions needed to be translated.
In the Content pattern you can nd structure indicating the strings, called also values, to be translated.
Properties Files
Properties les have the extension .properties. They are distributed over multiple directories of the different extensions.
Filename Pattern
.properties
Content Pattern
key=value
To Be Translated
value
There are different kinds of properties les each focusing on a different kind of object:
Types.
UI Components.
Messages.
Cockpits.
Type Driven Files
Filename pattern
extension -locales_ languagetag .properties
This is custom documentation. For more information, please visit the SAP Help Portal
198
5/27/2022
Content pattern
type.personobjectclassenum.name=PersonObjectClassEnum
Example
ldap-locales_en.properties
type.personobjectclassenum.name=PersonObjectClassEnum
type.personobjectclassenum.description=
type.personobjectclassenum.person.name=Person
type.personobjectclassenum.person.description=
type.personobjectclassenum.posixaccount.name=posixAccount
type.personobjectclassenum.posixaccount.description=
UI Component Driven Files
Filename
locales_ languagetag .properties
pattern
Content
tab.ldapcon g.enhanced=Enhanced Settings
pattern
Example
locales_en.properties
tab.ldapconfig.basics=Basic Settings
tab.ldapconfig.enhanced=Enhanced Settings
section.ldap=LDAP
section.ldap.test.connection=Connection Test
tab.ldapconfig.settings=LDAP
section.ldap.login=Login
section.ldap.jndi=JNDI
section.ldap.pool=Pool
section.ldap.internal=Internals
action.testldapconfiguration=Test
action.ldapconnection.notyetcreated=Item not created\!
action.ldapconnection.succesfull=Connection test successfull\!
action.ldapconnection.failed=Connection test failed\!
b2bcommercegroup.units.description=B2B Units are nodes of a B2B Organization such as a company or department
b2bcommercegroup.customers.description=Customer who are members of a B2B Organization who make purchases for the B2B Organization
type_tree_ldifimportwizard=Basic Import
Messages Files
Filename pattern
extension -messages_ languagetag .properties
Search for: messages.properties or messages_en.properties
Content pattern
paymentOption.billingInfo.validation.noLastName=Missing last name
Cockpit i3 Files
These les are like the UI component type les which might include acronyms such as ba = browser area or na = navigation area.
Filename pattern
i3-label.properties
Content pattern
attribute_pricecalculationdate = Price calculation date
Example
i3-label.properties
ba.constraint_browsermodel_label=Validierungsregeln
ba.constraint_pojo_browsermodel_label=POJO Validierungsregeln
mcc.login.login = Log in
mcc.login.logout = Log out
importcockpit.perspective.job=Jobs
importcockpit.perspective.mapping=Mapping
importcockpit.navigationarea.jobhistory=Execution history
attribute_pricecalculationdate = Price calculation date
attribute_root_chapter = Root Chapter
attribute_status = Status
attribute_subtitle = Sub Title
attribute_subtitle2 = Subtitle 2
attribute_title = Title
 Note
The i3-label.properties do not have _en language tag in the lename.
Welcome ZUL Files
This is custom documentation. For more information, please visit the SAP Help Portal
199
5/27/2022
Welcome ZUL les are XML les included with the cockpit extensions. It regards the following cockpits:
Print Cockpit — until version 4.6.0
CMS Cockpit — until version 4.6.0
Import Cockpit — until version 4.6.0
BTG Cockpit — until version 4.5.0
Welcome ZUL les need to be translated separately for the indicated versions only. Since then all contained strings have been moved to separate i3-label_ languagetag
.properties les.
There is a separate le for each language.
Filename pattern
welcome_ languagetag .zul
Search for: .zul and welcome
To Be Translated
Strings starting with:
value="
toolbarbutton label="
Link names before </h:a>
MCC ImpEx Localization Files
MCC ImpEx localization les are text les with names, for example essentialdata_mcc_links_en.impex. They can be opened like CSV les in order to display them in
the column structure. They contain strings for the UI of the SAP Commerce Commerce Cockpit.
Filename pattern
essentialdata_mcc_links_ languagetag .impex
Search for: mcc_links and .impex
To Be Translated
Indicated columns
Cockpit UI Element Con guration XML Files
Cockpit UI element con guration les are XML les with names such as Editor_Product_ProductManager.xml. They are included in the cockpit extensions.
These les contain source text and translations for all languages.
Filename pattern
text _ text .xml or text _ text _ text .xml
Search for: .xml.
The le contains <label lang="en". All related les are XML les with one of these
root tags:
<editor
<advanced-search
<list-view
<wizard-con g
They are located in the ${HYBRIS_BIN_DIR} / extension /resources
directory of a cockpit-like extension such as cockpit extension,
productcockpit extension, cmscockpit extension. But they also can
be found in other extensions, for example sampledata extension or
hyend2 extension.
To Be Translated
The following tags indicate strings that have to be translated: <label lang="en"> Source
language text </label>.
The corresponding translations are stored below in the same le: <label lang=" languagetag
"> Language translation </label>.
For example: <label lang="fr"> French translation </label> <label lang="de"> German
translation </label> <label lang="ja"> Japanese translation </label>
Related Information
Character Encoding Requirements for Localization Files
Java Message Service (JMS)
This is custom documentation. For more information, please visit the SAP Help Portal
200
5/27/2022
Java Message Service (JMS) offers an asynchronous approach to (possibly remote) method invocation, that complements the synchronous solutions offered by RMI,
Hessian/Burlap, Spring HTTP Invoker, and Web services.
About JMS and Synchronous and Asynchronous Method Calls
JMS is a means of invoking method calls in an asynchronous way. This is a different concept to web services, for example, which are invoked in a synchronous way. In a
synchronous method call, the client dispatches the call and then waits until the service has completed the task. Graphically, this can be interpreted as follows:
In this scenario when the client makes a call to a service it waits until that service has completed before proceeding further. Often this is the desired behavior but brings with
it potential issues:
Perhaps the service takes a long time to run leading to perceived "hanging" in the client thread.
Perhaps the client does not really need to wait for the service to end before proceeding.
The service can be called from any number of clients at the same time, but perhaps the service is CPU intensive and we must ensure that only two such processes can
run at any one time on any one CPU.
Perhaps certain clients should have a higher priority, and be able to trigger their service to run before other clients with lower priority.
Using JMS to Overcome Issues with Synchronous Calls
While these points can all be addressed to some extent with the synchronous approaches, JMS offers a neat solution to all of these points and more.
JMS is based on the notion of messages that are sent from a client to a message broker (for example ActiveMQ). This message broker's job is to then forward those
messages to one or more message listeners, which then perform some task as directed by the message's contents. The message broker handles the persistence of
messages (so that none is lost if a system crashes) and is transaction aware (so that the service that is called can be run within a transaction if desired).
Once the client has sent the message, it continues rather than waiting for the service to complete. This offers a powerful means for distributing possibly CPU-intensive tasks
over both time and over multiple computers.
The message broker can contain many "buckets" into which messages are placed, called Queues and Topics. Queues are used when we would like only one service to act upon
a message. Topics are suitable for broadcasting messages to one or more services. Which services receive messages from which Queues and Topics, is speci ed when
con guring the Message Broker.
Bene ts
JMS has several bene ts that complement the problems listed above:
It does not matter if the service takes a long time to execute, as the client is not waiting for it to complete.
While the message broker may have received many messages in one go, it passes the message on to the service only when the service is ready. This helps avoid CPU
overloading on the service.
This is custom documentation. For more information, please visit the SAP Help Portal
201
5/27/2022
Should a service crash (or be unavailable for what ever reason) the message broker ensures that all messages are persisted and guarantees their delivery when the
service is back up.
It is possible to prioritize messages such that some clients messages can "jump the queue". (While this is not strictly possible with ActiveMQ, there is a way to work
effectively simulate it)
The message broker can vary its output bandwidth, so for example ensuring that a maximum of three service jobs run on one CPU at any one time.
The message broker is transaction aware so that the service can run within a transaction.
Should a service throw an exception upon receipt of a message, you can specify how many times the broker should resend that message.
Should a service repeatedly thrown an exception upon each receipt of one message, we can specify how many retries are allowed before that message is sent to a
"Dead letter Queue" where it can be analyzed later by support.
As JMS has been a part of the Java Enterprise Edition for many years, it is fully supported by Spring.
Integration Guide
Every project is different and has individual requirements. Therefore, SAP Commerce cannot provide a customized, out-of-the-box standard solution for JMS integration. The
setup you are going to choose for JMS integration depends on system architectures, system landscapes, and other project-related requirements. In the end, you have to
de ne and set up the best-suited JMS integration setup depending on your speci c requirements.
To help you getting started, SAP Commerce provides two aspects of JMS:
SAP Commerce contains the JMS framework for you to use out-of-the-box.
Logging
Logging is an important part of software development. It helps you to understand the behavior of applications.
SAP Commerce comes pre-bundled with Log4j 2 logging framework, which you can use to debug your application. Remember that it is important to log statements that go
to your database.
For more information, see:
Logging With Log4J
Upgrading to Log4j 2
JDBC Logs from Database Statements
This is custom documentation. For more information, please visit the SAP Help Portal
202
5/27/2022
Upgrading to Log4j 2
SAP Commerce is shipped with the Apache Log4j 2 logging framework. Since Log4j 2 isn't compatible with its previous version, we provide instructions on how to handle
upgrading your extensions. We also summarize the changes done in the Platform to support Log4j 2.
Implementing Log4j 2
Log4j 2 is now the standard logging framework in SAP Commerce and you can use it either with SLF4J or directly.
We recommend that you use the Simple Logging Facade for Java (SLF4J) as a logging API for Log4j 2 serving as implementation:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
final Logger slf4jLogger = LoggerFactory.getLogger(LoggingFrameworksBridgeTest.class);
slf4jLogger.error("slf4j error");
You can also use the Log4j 2 API directly:
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
final Logger log4j2Logger = LogManager.getLogger(LoggingFrameworksBridgeTest.class);
log4j2Logger.warn("log4j2 warn");
It is not necessary to change the existing code that uses the Log4j API because all logs are redirected to Log4j 2.
Con guring Log4j 2
You can con gure Log4j 2 using multiple different formats.
Currently, we support the xml and the properties formats of SAP Commerce. For con guration details, consult the Log4j 2 official documentation.
To specify your Log4j 2 xml con guration le, set the xml le containing the con guration as a value for the log4j2.config.xml property, for example
log4j2.config.xml=hybris-log4j2.xml. This le must exist on classpath. XML con guration cannot be merged from multiple les.
As a second option, you can use the properties syntax. Specify all properties using the standard SAP Commerce properties. They must have the log4j2 pre x. The
/bin/platform/project.properties le contains an example of how to con gure loggers. Con guration is merged in the standard SAP Commerce way, therefore it is
possible to con gure speci c loggers for each extension - which isn't possible using the xml syntax.
This is custom documentation. For more information, please visit the SAP Help Portal
203
5/27/2022
Example of syntax of the old type:
log4j.logger.de.hybris.platform.servicelayer.hmc=warn, CONSOLE
Example of syntax of the new type:
log4j2.logger.hmc.name = de.hybris.platform.servicelayer.hmc
log4j2.logger.hmc.level = warn
log4j2.logger.hmc.appenderRef.stdout.ref = STDOUT
 Note
Note the log4j2 pre x in the code.
It is not necessary to specify appenders, lters or loggers property as it is generated automatically during startup.
Changes in Commerce Platform
SAP Commerce shipped its own HybrisLogger that extended Log4j logger and provided a SAP Commerce custom functionality to listen to and lter the
HybrisLogListener and HybrisLogFilter log events. Now HybrisLogger acts only as a wrapper and delegates all logging to SLF4J that in turn uses Log4j 2 as an
implementation. The mentioned HybrisLogListener and HybrisLogFilter functionality, however, is retained and its handling was moved to customized
HybrisLog4j2Logger.
Upgrading Extensions
Don't change code, unless you have earlier used Log4j-speci c functionalities. For example, change MDC to either SLF4J MDC or Log4j 2 MDC. HybrisLogListener and
HybrisLogFilter should work as they used to. If a custom appender was created, move it either to LogListener or to the custom plugin for Log4j 2.
Logging With Log4J
SAP Commerce comes pre-bundled with a version of the Log4J logging framework. The Log4j version delivered with SAP Commerce comes as a JAR library named log4j-
xx.jar:
Log4j Basics
 Note
This section will try to give you only a rough overview on Log4j. You will very likely need more in-depth documentation to actually implement this logging framework. The
Log4j website
should be a good starting point for you.
Log4j is an open source project maintained by the Apache Foundation. It is available for many programming languages other than Java as well, such as C, C++, C#, Ruby, and
others.
There are three main concepts in Log4j: loggers, appenders, and layouts. Loggers are objects that wait for an event to happen and put out a message then. Whether a
certain event really triggers a certain logger or not depends on that event's importance, compared to the logger's importance threshold. If the event's importance (called
priority or log level in Log4j) is equal to or higher than the logger's log level threshold, that logger prints out a message. If the event's log level is lower than the logger's log
level, the logger is not triggered.
Log4j differentiates ve such log levels (in ascending order): DEBUG, INFO, WARN, ERROR, FATAL, NONE. The following graphic shows the event log level that triggers a
certain logger. Green means triggered, red means not triggered. A logger set to NONE will never be triggered.
As you can see from the diagram, a logger set to the DEBUG level will report any event that is passed to it, a logger set to FATAL will only report events of level FATAL.
Another important thing about loggers is that they inherit their log levels to their children. If you have a logger that is set to the INFO level and derive a logger from it, the
new logger will also be set to the INFO level by default. In other words: a logger that is not assigned a level explicitly will receive its level from its closest ancestor that has a
level assigned to it.
For example, if you create a logger log1 with level FATAL, then derive a logger log2 from it, log2 will have the level FATAL as well. Now, if you set log2 to the INFO level and
derive another logger log3 of it, then log3 will have the INFO level, since log2 is log3 's closest ancestor.
 Tip
This is custom documentation. For more information, please visit the SAP Help Portal
204
5/27/2022
Logger creation order is arbitrary
Loggers may be con gured and created in any order. It is even possible to create loggers whose parents have not yet been created. A logger will automatically put itself in
its correct place in the inheritance hierarchy once its ancestors are all there.
Using Loggers
1. import the org.apache.log4j.Logger class,
2. call the static class Logger 's getLogger( String name) method ( Log4J API
)
3. call the logger:
${instancename}.${logLevel}("${message}");
An example listing:
// import the package
import org.apache.log4j.Logger;
...
// creating the logger instance
static final Logger log = Logger.getLogger( "my.log4j.topic" );
...
log.fatal("Oh my god! This is so wrong!");
log.warn("Hmmm - something didn't work out...");
log.info("Just for you to know.");
...
This listing creates three so-called log requests. A log request is "enabled" if it triggers the logger (that is, if its log level is higher than the trigger's log level) and "disabled" if
it does not trigger the logger (that is, if its log level is lower than the trigger's log level).
The more sensitive the logger log is set, the more log levels it will respond to. For example, if you set it to the FATAL level, it will only report the rst event (FATAL level). If you
set it to DEBUG, it will report all three lines of logging information.
Another, more practical listing:
// import the package
import org.apache.log4j.Logger;
...
// creating the logger instance
static final Logger log = Logger.getLogger( "my.log4j.topic" );
private int test=27;
...
try {
someMethod(test);
}
catch (NullPointerException NPEx) {
log.fatal("test has value null!");
test = 0; // to avoid further trouble
break;
}
catch (Exception Ex) {
log.warn("Something went wrong, but at least test is not null!");
}
if( test == 27)
log.debug("test is 27");
else
log.info("test is different from 27!");
...
An appender basically is an output destination. It allows sending logging information to the Console, to (log) les, to certain Unix daemons, some GUI elements, and so on.
One logger may have several appenders and therefore log into several destinations at once. Appenders are also inherited from parents to their children, so if you create a
logger log1 and assign an appender app1 to it, any other loggers you derive from log1 (say, log2 and log3) will also have the appender app1 assigned to them. Now, if you add
an appender app2 to log2 and derive a logger log4 from log2, log4 will have both appenders, app1 and app2. This is called the additiveness of loggers. This additiveness may
be disabled for a logger by setting its additiveness ag to false.
Finally, there are layouts. These are templates of how to format the logger's output. They mainly consist of switches to include (or not) text patterns like the program's
running time, the name of the logger, etc. For a more extensive list, please refer to the PatternLayout page
in the Log4j documentation.
Con guring the Log Environment
Con gure the loggers for your application is done via the project.properties le located in the ${hybrishome}/bin/platform directory (please refer to here for
the properties documentation). The following sample excerpt is taken from an out of the box SAP Commerce project.properties le and consists two major Log4Jrelated sections:
the logger con guration section and
the appender con guration section
#################### LOG4J SETTINGS ########################
#
This is custom documentation. For more information, please visit the SAP Help Portal
205
5/27/2022
# Log4J Settings
#
############################################################
# --- just put your logging statements into your local.properties
# --- see examples below for how to log different classes to different
# --- appenders in different levels
log4j.appender.FILE=org.apache.log4j.RollingFileAppender
log4j.appender.FILE.File=../logs/catalina.log
log4j.appender.FILE.MaxFileSize=10MB
log4j.appender.FILE.Threshold=DEBUG
log4j.appender.FILE.MaxBackupIndex=100
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.ConversionPattern=%d %-5p [%X{RemoteAddr}] (%X{Tenant}) (%X{CronJob}) [%c] %m%n
log4j.appender.ACCESSFILE=org.apache.log4j.RollingFileAppender
log4j.appender.ACCESSFILE.File=../logs/attributeaccess.log
log4j.appender.ACCESSFILE.MaxFileSize=100MB
log4j.appender.ACCESSFILE.Threshold=DEBUG
log4j.appender.ACCESSFILE.MaxBackupIndex=100
log4j.appender.ACCESSFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.ACCESSFILE.layout.ConversionPattern=%d %-5p [%X{RemoteAddr}] (%X{Tenant}) [%c] %m%n
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.Target=System.out
log4j.appender.CONSOLE.Threshold=DEBUG
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%-5p (%X{Tenant}) (%X{CronJob}) [%c{1}] %m%n
log4j.rootLogger=info, FILE, CONSOLE
log4j.logger.your.package=debug
# send all accessor log into ACCESSFILE only -> have to switch off additivity flag !
log4j.logger.hybris.attribute.accessor=warn, ACCESSFILE
log4j.additivity.hybris.attribute.accessor=false
# --- some useful logging statements and settings
# ----------------------------------------------------------------# --- for debugging flexiblesearch statements:
#log4j.logger.de.hybris.platform.jalo.flexiblesearch=debug
# --- for logging all flexiblesearch statements with DEBUG into file, but with info on console
# --- the additivity setting will only give the logger to the own configured logger and not
# --- (in 'addition' to that) to the root logger
#log4j.additivity.de.hybris.platform.jalo.flexiblesearch=false
#log4j.logger.de.hybris.platform.jalo.flexiblesearch=debug,FILE
# --- for debugging cronjobs and triggers:
#log4j.logger.de.hybris.platform.cronjob.jalo.TimerTaskUtils=debug
#log4j.logger.de.hybris.platform.cronjob.jalo.CronJobTimerTask=debug
# --- for debugging switching of tenants:
#log4j.logger.de.hybris.platform.core.Registry=debug
#log4j.logger.de.hybris.platform.core.AbstractTenant=debug
#log4j.logger.de.hybris.platform.core.MasterTenant=debug
#log4j.logger.de.hybris.platform.core.SlaveTenant=debug
 Note
Explicitly mapped elds
There are implemented explicitly mapped elds,which might be used in ConversionPattern attribute for a speci c appender.
Now there are introduced three of them :
RemoteAddr, returns address of remote host request being processed;
Tenant, current tenant for logic being performed;
CronJob, code of CronJob which the logic is being perfomed in.
Disabling Additivity to Prevent Duplicate Logging
In some cases, logging output is executed twice to a log destination. This is a side effect of the Log4j additivity which is active for each logger by default.
Example:
You have a logger for your package my.base.packagename. And you have a logger for another package my.base.packagename.extension. These loggers are con gured as
follow:
# --- Logger 1
log4j.logger.my.base.packagename=info, appconsole
# --- Logger 2
log4j.logger.my.base.packagename.extension=debug, appconsole
This is custom documentation. For more information, please visit the SAP Help Portal
206
5/27/2022
Then, every logging statement for my.base.packagename will be executed once and every statement for my.base.packagename.extension will be executed twice - one time
for the de ned logger and one time for the inherited logger my.base.packagename.
You can prevent this second execution by deactivating the additivity of the second de ned logger:
# --- Logger 1
log4j.logger.my.base.packagename=info, appconsole
# --- Logger 2
log4j.logger.my.base.packagename.extension=debug, appconsole
log4j.additivity.my.base.packagename.extension=false
Related Information
http://logging.apache.org/
Con guring the Behavior of SAP Commerce
Colored Logging in Console
Color logging improves the readability of the information displayed in the console when running SAP Commerce.
Enabling Colored Logging
The colored logging in console is enabled by default on all platforms except on Windows, which doesn't support it natively.
To enable ANSI colors support on Windows add the http://repo1.maven.org/maven2/org/fusesource/jansi/jansi/1.9/jansi-1.9.jar to your application
and Log4j 2 will automatically make use of it when writing to the console. ANSI colors on Windows without jansi is disabled.
Disabling Colored Logging
To disable the colored logging, change the value in the local.properties le:
ansi.colors=false
Modifying Colors
This is custom documentation. For more information, please visit the SAP Help Portal
207
5/27/2022
The simplest way to change colors for different log levels is to set new values in the local.properties le.
Let us consider the following example:
log4j2.appender.console.layout.pattern = %highlight{%-5p [%t] %X{RemoteAddr}%X{Tenant}%X{CronJob}[%c{1}] %m%n}{FATAL=white, ERROR=red,
It sets the colors by using the {FATAL=white, ERROR=red, WARN=blue, INFO=black, DEBUG=green, TRACE=blue} style pattern provided at the end. The
pattern from the example sets FATAL level to white, error to red, warning to blue, info to black, debug to green and trace to blue.
For details on different values for SGR (Select Graphic Rendition) parameters see Wikipedia on ANSI escape code
, section Colors.
The table below presents default values for available log levels:
Parameter
fatalColor
errorColor
warnColor
infoColor
debugColor
traceColor
Default color
Bright red
Bright red
Yellow
Green
Cyan
Black
JDBC Logs from Database Statements
SAP Commerce sends database statements to query and modify data in the database. You can create a record of these statements. The process of recording the
statements is called JDBC logging.
SAP Commerce uses JDBC to connect to databases. As a JDBC log contains information on statements, execution times, and other information, you can use it to identify
and remedy performance bottlenecks on the database.
Understanding a JDBC Log File
In a JDBC log le, each line is an individual logged statement. Each line consists of a number of bits of information, delimited by the pipe character ( | ). The following example
entry is broken down into multiple lines so that it is easier to read:
34|master|091106-15:01:04:136|1 ms|statement|SELECT item_t0.PK FROM tasks item_t0
WHERE item_t0.p_failed = ?|SELECT item_t0.PK FROM tasks item_t0 WHERE item_t0.p_failed
= 0
Each line of a JDBC log le consists of the following elds (from left to right):
Field Name
Field Description
Value in Sample Line
Thread ID
The ID of the thread that executed the statement.
34
Datasource ID
The ID of the used datasource.
master
Start Time
Date and time when the statement was started.
091106-15:01:04:136
Elapsed Time
Amount of time that the execution of the statement took.
1 ms
Category
The category of the statement. Possible values:
statement
statement, commit, rollback.
Prepared statement
Each statement sent to the database has to be compiled.
When executing a lot of similar statements (for example,
when the only difference is in parameters) prepared
statements are used for better performance. The prepared
SELECT
item_t0.PK
FROM tasks item_t0
WHERE item_t0.p_failed
= ?
statement is precompiled without parameters and then can
be reused many times.
SQL statement
The actual SQL statement that was executed on the
database.
SELECT
item_t0.PK
FROM tasks item_t0
WHERE item_t0.p_failed
= 0
Enabling and Disabling JDBC Logging
You can enable or disable JDBC logging by using SAP Commerce Administration Console, Java code, or through the con guration properties le.
Enabling or disabling JDBC logging in SAP Commerce Administration Console has a runtime effect only - logging is set back to default after an SAP Commerce restart.
Enabling or disabling JDBC logging by using Java code has a runtime effect only - logging is set back to default after an SAP Commerce restart.
Enabling or disabling JDBC logging through the con guration properties le has a persistent effect - logging is enabled or disabled after an SAP Commerce restart.
 Note
JDBC Logging Reduces Performance
Because every single database statement is logged, the database performance is reduced with JDBC logging enabled. Enable JDBC logging only when needed.
This is custom documentation. For more information, please visit the SAP Help Portal
208
5/27/2022
Enabling JDBC Logging in SAP Commerce Administration Console
In SAP Commerce Administration Console, you can enable or disable JDBC logging on the Monitoring Database JDBC logging page.
Enabling JDBC Logging Using Java Code
To enable JDBC logging in your Java code, add the following line:
de.hybris.platform.util.Config.setParameter("db.log.active", "true");
To disable JDBC logging in your Java code, add the following line:
de.hybris.platform.util.Config.setParameter("db.log.active", "false");
This is an example of how to enable and disable JDBC logging:
private void myMethod()
{
de.hybris.platform.util.Config.setParameter("db.log.active", "true");
myProductModel.setCode("ModelCode");
modelService.save(myProductModel);
de.hybris.platform.util.Config.setParameter("db.log.active", "false");
}
Enabling JDBC Logging Through a Properties File
To ensure that the logging setting remains enabled or disabled persistently, set an appropriate property value in the local.properties le.
To enable JDBC logging, use db.log.active=true.
To disable JDBC logging, use db.log.active=false.
To specify a logger class explicitly, specify the fully quali ed class name of the logger class to the db.log.loggerclass con g property, such as
db.log.loggerclass=de.hybris.platform.jdbcwrapper.logger.FileLogger.
For details about the local.properties le, see Con guring the Behavior of SAP Commerce.
Related Information
http://en.wikipedia.org/wiki/JDBC
http://en.wikipedia.org/wiki/JDBC_driver
Third-Party Databases
Performance Tuning Overview
Tips on Performance Tuning
Media
SAP Commerce supports media les of all sorts. A media can be anything that can be saved on a le system, such as a Flash animation le, a JPEG image, an MPEG video
le, a CSV le, a text le, an XML le, and other. These medias can be stored in various locations. You can keep them locally or remotely using Amazon S3, Windows Azure
Blob or MongoDB GridFS solutions. Access to your medias can be also secured.
The topics covered in this section include:
Media Guide
Media Storage Overview
Secure Media Access
Media Guide
SAP Commerce supports media les of all sorts. A media can be anything that can be saved on a le system, such as a Flash animation le, a JPEG image, an MPEG video
le, a CSV le, a text le, an XML le, and other.
A media item in SAP Commerce is not a physical le, but a reference to that le.
A media item in SAP Commerce is a container object that holds a reference to a le. That is, a media item in the SAP Commerce is not a le itself, but a reference to a le.
The actual le can be stored in SAP Commerce or may be located on a remote server or system.
Important Attributes of a Media
A media item has an identi er and is assigned to a catalog version. The identi er is used for the logical reference, such as, for matching a product identi er. Media items can
be synchronized along with the catalog version to which they are assigned. That way, you can make sure that product images match the catalog version. If you assign a
This is custom documentation. For more information, please visit the SAP Help Portal
209
5/27/2022
media item to a product using the Hybris Management Console, the Hybris Management Console automatically sets the catalog version of the product to the newly
uploaded media item.
In addition, a media item has an URL that points to the location of the actual le. To reference a le in an SAP Commerce application (for example, in the SAP
StoreFoundation), you need to retrieve and use the media item's URL.
In the graphic, the catalog Clothescatalog contains one catalog version (Online), which holds one product (30124). This product references two media items; 30124_medium
and 30124_thumbnail. The media item, 30124_medium references the le, 30124_medium.jpg, whereas the media item, 30124_thumbnail references the le,
30124_thumbnail.jpg.
One File per Media, Several Media per File
A single media item in SAP Commerce references one single le only. However, different media items can reference the same le, as outlined in the Synchronization of
Media Items section below. For more information about grouping media items, refer to the Grouping Media via Media Containers section below.
In the screenshot on the right side, both the full-size image and the thumbnail are individual media items and, by consequence, individual les. Even though both images are
related, they are not represented by the same media item. This is indicated by:
The individual lenames for the images. For example: 30124_medium.jpg and 30124_thumbnail.jpg
The individual URLs for the actual image. For example: /medias/sys_master/8451288199586880.jpg and
/medias/sys_master/8451288199586384.jpg
 Note
Storing Many Files for One Media Item
You can have more then one le matched to one media item. For more details, see the Storing Many Files for One Media Item document.
This is custom documentation. For more information, please visit the SAP Help Portal
210
5/27/2022
Using Localized Media
Media items in SAP Commerce are not localized by default. A media item does not reference individual les depending on the language. Instead, the referenced le is the
same for all languages. To use localized les, you need to use an attribute of type localized:Media or a RelationType in the items.xml le. The screenshot to the right
shows the representation of an attribute of type localized:Media in the Hybris Management Console.
Usage of Media Items in the SAP Commerce
Below are some examples of media items in SAP Commerce:
SAP Commerce Aspect
Usage of Media items
Links
SAP Media Conversion
Integrated with an open source software ImageMagick to
Media Conversion
create, edit, compose, or convert almost all available
bitmap image formats. Extraction of the metadata like IPTC
and Exif metadata of bitmap images.
SAP WCMS Module
Images in paragraphs
WCMS Module
CronJob
CronJob logs
The cronjob Service
ImpEx
ImpEx logs, (temporary) dump les
ImpEx
SAP Print Module
Images of products, Werk2 plugin scripts
Print Module
Product
Images
Synchronization of Media Items
During the synchronization of a catalog version, all the media items in the source catalog version are copied. After synchronization, every media item is available twice: once
in the source catalog version, and once in the target catalog version.
However, the les referenced by the media items will not be duplicated and are available only once. Instead of creating an individual copy of a Media-item-referenced le in
the target catalog version, the Media item in the target catalog version holds a reference to the original le. The concept is similar to symbolic links.
For more information, see Synchronizing Catalog Versions.
For example, in the graphic, there is one catalog version Staged, which is used as the source catalog version for synchronization. This Staged catalog version holds one
product, 30124. The product 30124 holds two Media items, 30124_medium and 30124_thumbnail. Each Media item has an individual image le, 30124_medium.jpg and
30124_thumbnail.jpg, respectively.
After a synchronization from Staged to Online, the product 30124 is available twice: once in the Staged catalog version, and once more in the Online catalog version. The
Media items, 30124_medium and 30124_thumbnail are also available twice. However, the actual les represented by the media items, 30124_medium.jpg and
30124_thumbnail.jpg are also available once. The media items in the Online catalog version do not have an individual copy of the les, but holds a reference to the
30124_medium.jpg and 30124_thumbnail.jpg les instead.
This is custom documentation. For more information, please visit the SAP Help Portal
211
5/27/2022
When you use different catalog versions in a synchronization scenario, you have to modify media every now and then to match an updated assortment. If you modify a media
le in the source catalog version, SAP Commerce ensures that references to the original media le remain correct for target catalog versions. If the media le was simply
overwritten and no references were updated in the process, then the target catalog version would still hold the reference to the media le of the source catalog version. As
this le would have been overwritten, however, the target catalog version would then wrongly reference the new media le. In essence, you would end up with the target
catalog version also showing the new media, when it should be displaying the old media.
Therefore, SAP Commerce modi es the references of the media item to hold the old media. Technically, this is done using the dataPK attribute of a media item. Do not
modify this attribute or the reference mechanism may fail to work correctly. This reference consistency mechanism is fully automated and transparent. You do not have to
worry about maintaining references manually. Just modify, upload, scale, convert your images to your liking, and SAP Commerce will deal with the references.
In the graphic, the original 30124_medium.jpg media le in the Staged catalog version was replaced by a modi ed le. The 30124_medium media item in the Online
catalog version still references the original 30124_medium.jpg le. SAP Commerce now makes sure that the 30124_medium media item in the Staged catalog version
and the 30124_medium media item in the Online catalog version each reference the respective 30124_medium.jpg le.
During a synchronization, the 30124_medium media item in the Online catalog version will be modi ed to also reference the new 30124_medium.jpg le. This means that
after a synchronization, the previously used 30124_medium.jpg le will no longer be used by either catalog version.
Using a Media Item
Since a media item in SAP Commerce is a container rather than an actual le, you need to reference the actual location of the le represented by the media item. The
location is held in the media item's url attribute.
<%
Media media = ...
out.println("<img src=\"" + media.getURL() + "\"/>");
%>
Controlling Access Using Media Folders
Media Folders enable you to store individual media les in different directories on the le system. Structuring media les in this way is an effective and at the same time
simple approach to enable access control for the contained media les. Also, see the MediaFolders document. Since media folders pertain to media les, they do not provide
a logical grouping functionality for media items.
Storing Media Files
Media les are stored in standard directories located in ${HYBRIS_DATA_DIR}/media directory in structure of subfolders. You can enable this way of storing les for your
custom MediaFolder and also change the default depth of subfolders that are generated for each media le. See also the MediaFolders document.
Structuring Media Items
SAP Commerce enables several means of grouping and structuring media items:
Assigning a Media Format to media items to keep track of the format of the media
Assigning multiple media to a Media Container to group the media logically
Assigning multiple media formats to a Media Context to de ne a replacement list for media formats in a given context
Keeping Track of Formats via Media Formats
This is custom documentation. For more information, please visit the SAP Help Portal
212
5/27/2022
Each media item can have one Media Format assigned. A Media Format is simply a tag assigned to a media item, called a logical label. It does not invoke any functionality
such as automatic conversion. For example, if a media item has a "50x50px" media format assigned to it, it doesn't mean the le is necessarily 50 by 50 pixels in size, nor has
been converted or scaled to 50x50 pixels automatically. It only means the media has the "50x50px" label assigned to it. You have to provide any conversion or re-scaling
functionality explicitly by using a Media Asset Management system.
Grouping Media Using Media Containers
Media items in SAP Commerce can be assigned to individual Media Containers for logical grouping. One single media item can only be assigned to one Media Container,
which holds all media items that are different formats of one certain media item. For example, a Media Container can hold all media items of a certain product, no matter
what le type or measurement of the actual les. In essence, a Media Container is a rule of which media items to use for which media format. A media item can only be
assigned to a Media Container if the media item has a media format set.
A Media Container is intended primarily for images. Generally, product-relevant media items of which, only one version is available at any given time such as data sheets,
spare-parts lists, and manuals in PDF format are not a useful eld of application for Media Containers. However, if you have product data sheets in different versions such as
individual layouts for Letter and DIN A4 formats, then a Media Container may be useful.
In this example, the 30125_medium media item is in Picture Format - picture - 7, the 30125_thumbnail media item is in Thumbnail Format - thumbnail - 8, and the 30125
media item is in Original Media Format - original - 6.
This graphic shows the basic structure. The media 30125_thumbnail, and 30125_medium are different versions (that is, media formats) of one single media: 30125. Each of
the media has a media format. The media container re ects the fact that these media are related by holding the media and their respective media format. The media
container can look up which of its media is available in a given media format. That way, it is possible to get a media in a certain media format using the media container.
Using the media container, you do not have to explicitly retrieve the media in a certain media format. You can use the MediaService method,
getMediaByFormat(MediaModel, MediaFormatModel) to get the media representation in a given format. The media service will look for the media container and
return media in the speci ed format, if it is available. This is fully transparent and you do not have to use media container explicitly. See the example:
final MediaModel mediaModel = ...
final MediaFormatModel formatModel = ...
final MediaModel mediaInRequiredFormat = mediaService.getMediaByFormat(mediaModel, formatModel);
In the example above, if the media item, 30125 were asked to return its representation in the Picture Format - picture - 7, the media container would return the
30125_medium media item.
For more information, see Handle Medias Using the MediaContainer.
Grouping Media Formats Using Media Contexts
Media Contexts are to Media Formats what Media Containers are for Media items. It is a rule on which media formats to use instead of others in any given context. In
essence, a Media Context tells the user, If you run across media items in this media format, replace them with the media items in the other media format.
A Media Context therefore de nes a mapping of media formats. One entry holds the media formats to replace, and the other entry holds the media format to use as a
replacement.
For example, the SAP Print module makes use of Media Contexts, because a Print publication uses either only low-resolution images for preview, or high-resolution images
for publication rendering at any given time. In this case where only one kind of media formats is used out of a number of media formats, a Media Context de nes that either
low-resolution or high-resolution images are to be used.
For example, the Media Context highres in the screenshot de nes these replacement rules:
This is custom documentation. For more information, please visit the SAP Help Portal
213
5/27/2022
Source Media Format
To be Replaced by Media Format
Original Media Format - original - 6
Original Media Format - original - 6
Picture Format - picture - 7
Original Media Format - original - 6
Thumbnail Format - thumbnail - 8
Original Media Format - original - 6
This assures that for all images, the media in the Original Media Format - original - 6 media format is selected.
The following diagram shows the replacement table of the highres Media Context and of a lowres Media Context in a graphical way:
 Note
By factory default, media formats are unaware of Media Contexts and do not use them automatically. If you want to make sure that they are automatically used to
replace Media Formats, you need to implement this functionality explicitly.
Referencing Files of Media Items
SAP Commerce differentiates between the following means of referencing les for media items:
In the Using the MediaWeb for Media Storage and Web Requests section:
The le referenced by the media item is managed by the SAP Commerce MediaWeb. Where the MediaWeb actually keeps the les, such as in the MediaWeb itself, on
the local computer, on a network share is not signi cant in this case.
Using an URL:
Media items need to reference their le using a URL if the le is outside the SAP Commerce MediaWeb, such as:
In an image database
In a Media Asset Management system
In the classpath of a JAR le
Media URLs
The URL of a media item is constructed differently, depending if the access to a media item is secured on not:
Not secured URL pattern: ${server_address} : ${port} / localMediaWebRoot / realFileName ?context= encodedMediaContext Example:
http://localhost:9001/medias/someFile.jpg?context=NAYDCL3IGAZC6ZTPN4XGU4DHHI5DU4LXMVZHI6JRGIZTINI.
 Note
For details on how the context string encodedMediaContext is created, see the LocalMediaWebURLStrategy.java le.
Using the unique PK of the media item in the URL ensures getting the correct item for a permission check. You can change the default securemedias pre x. For
more details, read the Secure Media Access document, section Adding SecureMediaFilter to Custom Web Application.
For more information, see Secure Media Access.
Legacy Support for prettyURL
This is custom documentation. For more information, please visit the SAP Help Portal
214
5/27/2022
You can use prettyURL, which is a SEO-friendly URL addresses. You can only use it for local media storage. It does not work for Amazon S3, Blobstore, or GridFS. This feature
is disabled by default and needs to be activated with the following key:
local.properties
media.legacy.prettyURL=true
With prettyURL disabled, an example URL looks like this: /medias/someFileName.jpg?
context=NAYDCL3IGAZC6ZTPN4XGU4DHHI5DU4LXMVZHI6JRGIZTINI
With prettyURL enabled, an example URL looks like this: /medias/sys_master/folder/h78/hd0/8796125986846/someFileName.jpg
For more information, see MediaFolders.
Using the ETag for Web Cache Validation
Whenever a media le is changed, the old le is removed and the new one is saved. Therefore, a new dataPK attribute is generated for the media. This solution allows the
use of a dataPK attribute as a unique ETag value that is used for web cache validation. The communication ow between a client and the SAP Commerce Server in the
diagram below shows how validation works in SAP Commerce:
Using the MediaWeb for Media Storage and Web Requests
The mediaweb extension is an extension in the Commerce Platform that serves these purposes:
Redirect Servlet:
The MediaWeb contains a Java Servlet that evaluates the path to where the media les are located and makes sure that HTTP and HTTPS requests are modi ed to
match that path.
Media File Storage Location (Optional):
The MediaWeb optionally is the place where the les of the media items can be saved. Files not saved in the MediaWeb have to be referenced using the URL.
This is custom documentation. For more information, please visit the SAP Help Portal
215
5/27/2022
For more information, see Wikipedia on Java servlet: http://en.wikipedia.org/wiki/Java_Servlet
.
Related Information
items.xml
Synchronizing Catalog Versions
SAP Commerce JavaDocs
Handle Medias Using the MediaContainer
A MediaContainer is a representation of a given Media and all its formats acquired in a conversion procedure. A MediaContainer can hold any number of MediaFormats
associated with the given Media. The main role of MediaContainer is to group Media and all its formats after making conversion of that Media. A MediaFormat is implied as a
media with changed format or resized dimensions.
Each of MediaContainer needs to have a unique quali er.
A MediaContainer enables you to provide conversion procedure: getting different formats of a given Media. You can de ne the MediaFormats in the ConversionGroups.
 Tip
To follow the concept of processing conversion of a media see mediaconversion Extension - Technical Guide document.
Using a MediaContainer via the SAP Commerce API
A media container offers simple way to retrieve / store a media objects in a speci ed media format. Simple example of using container and formats:
final MediaContainerModel mediaContainer = modelService.create( MediaContainerModel.class );
mediaContainer.setQualifier( "testContainer" );
final MediaFormatModel format1 = modelService.create( MediaFormatModel.class );
format1.setQualifier( "640x480" );
final MediaFormatModel format2 = modelService.create( MediaFormatModel.class );
format2.setQualifier( "1280x1024" );
final MediaModel mediaInFormat1 = modelService.create( MediaModel.class );
mediaInFormat1.setCode( "media1" );
mediaInFormat1.setMediaFormat( format1 );
mediaInFormat1.setMediaContainer( mediaContainer );
final MediaModel mediaInFormat2 = modelService.create( MediaModel.class );
mediaInFormat2.setCode( "media2" );
mediaInFormat2.setMediaFormat( format2 );
mediaInFormat2.setMediaContainer( mediaContainer );
modelService.saveAll();
Now you can get media in format2 from original one:
MediaModel retrievedMediaInFormat2 = mediaService.getMediaByFormat( mediaInFormat1, format2 );
Using a MediaContextModel you can specify xed mappings from one media format to another.
final MediaContextModel mediaContext = modelService.create( MediaContextModel.class );
mediaContext.setQualifier( "testContext" );
modelService.save( mediaContext );
final MediaFormatMappingModel mapping = modelService.create( MediaFormatMappingModel.class );
mapping.setMediaContext( mediaContext );
mapping.setSource( mediaInFormat1 );
mapping.setTarget( mediaInFormat2 );
modelService.save( mapping );
Now you can get media in format 2 from media in format 1:
MediaModel retrievedMediaInFormat2 = mediaService.getMediaByContext( mediaInFormat1, mediaContext );
MediaFolders
SAP Commerce allows specifying folders for media. That way, you can use the web server or application server to limit access to media les.
About Media in SAP Commerce
Media items in SAP Commerce can be just about any le that can be referenced. Unlike most other items (such as Products or Users) which are pure Java objects, Media
items have a physical representation somewhere on a le system: CSV les, images, Flash animations, ZIP les, MP3 les, etc.
Any media item in SAP Commerce consists of two aspects:
This is custom documentation. For more information, please visit the SAP Help Portal
216
5/27/2022
a physical le, located somewhere on the application server le system
an SAP Commerce object of the Media type that holds a reference to the physical le
Background
Media les for a web application can be security-sensitive data, and you may not want everybody on the World Wide Web to be able to see all of your media les. Some les
(such as product representation images, thumbnails, animated banners, etc) are ok for anybody to see. For other les (such as internal presentation les), you will want to
make sure that access is only granted if some means of identi cation is provided.
A very basic and effective means of access control is directory-based authentication. Here, a directory can only be accessed by users if the users identify themselves (for
example, by providing credentials such as a user name and a matching password). The same basic mechanism can be used to control access onto directories on a web
server. For the common Apache HTTP Server, for example, the mechanism is implemented in the form of .htaccess les. For details on the mechanism in place on your
application server and on how to specify access control settings, refer to the documentation of your application server.
Functional Principle of MediaFolders
SAP Commerce allows you to assign Media les to individual MediaFolders. Every MediaFolder results in an individual directory on the application server. Media assigned to a
MediaFolder are stored in the directory of the MediaFolder. Therefore, MediaFolders effectively allow using access control settings on Medias on a per-directory basis.
The actual, physical location of where Media les are deployed to depends on the application server in use. Refer to the documentation of your application server. If you use
the Apache Tomcat in exploded deployment mode, prebundled with SAP Commerce, the deployed Media les are located in the following location: ${HYBRIS_DATA_DIR}
/media. Then by default les are distributed between four default folders:
cronjob
hmc
impex
catalogsync
 Note
root Folder
You may also notice the existence of the root folder. It is not a physical folder stored on the application server. It is a name associated with the main media folder of the
currently activated tenant. In other words, if you are working on the master tenant, the root folder is the same as the sys_master folder.
The MediaFolders of the SAP Commerce installation are tenant-speci c, so that every individual tenant will have individual media folders. For every individual tenant, an
individual directory named sys\_ ${tenant} is created in the deployment directory of the application server. For example, you may have the following MediaFolders: cronjob,
hmc and impex, and the following tenants: master and junit. The deployment directory of the application server contains the following directories:
media
sys_master
cronjob
hmc
impex
sys_junit
cronjob
hmc
impex
Technical Implementation
This section describes technical aspects of the MediaFolder implementation.
MediaFolder Type
The MediaFolder type speci es the directory into which the physical media les are stored. The directory name is speci ed by the path attribute.
For more information, see SAP Commerce JavaDocs.
Media Type: MediaFolder Attribute
This is custom documentation. For more information, please visit the SAP Help Portal
217
5/27/2022
As part of the MediaFolder functionality, the Media type has a new attribute: MediaFolder. This attribute speci es the MediaFolder into which the media will be stored.
Moving Media Between MediaFolders
This section discusses various approaches of how to move Media between MediaFolders. The Hybris Management Console offers two different approaches to move Media
between MediaFolders. To move an individual Media, you can use the Media Editor. To move more than one Media, you can use the HMC SearchResultAction. Both
approaches use the MoveMediaWizard.
Moving an Individual Media
When you open a Media in the Hybris Management Console Editor Area, you can click on the Move Media attribute to open the MoveMediaWizard for the individual Media:
Moving Media from a Search Result
Select any number of medias you would like to move to a different MediaFolder.
Right-click on any search result in the Result Area.
Point on Actions, then click on Move Media.
MoveMediaCronJob
To move media les from one MediaFolder to another MediaFolder, you can use the MoveMediaCronJob. Upon execution, a MoveMediaCronJob automatically moves the
media les speci ed by the medias attribute to the directory speci ed by the targetfolder attribute.
 Note
Medias attribute not displayed in the HMC by factory default
The medias attribute might contain a very large number of media le references. Displaying literally thousands of media les in a single attribute editor element
results in very long Hybris Management Console pages,
can negatively affect system performance, such as
browser crashes
long responding times when clicking on any element of the attribute
Therefore, SAP Commerce does not display the medias attribute in the HMC by default.
The attribute can be set via the SAP API or via ImpEx. For the Hybris Management Console, use the Result Area action instead, which calls the MoveMediaWizard.
MoveMediaWizard
As the medias attribute of the MoveMediaCronJob is not displayed in the Hybris Management Console, you cannot conveniently use a CronJob to move a large number of
media les between MediaFolders. Instead, you can use a Result Area action to run a Wizard.
In the Wizard that opens, select the target MediaFolder from the Target Folder drop-down combo box.
This is custom documentation. For more information, please visit the SAP Help Portal
218
5/27/2022
Click the Start button.
After the Wizard has nished, click the Done button to close the Wizard.
Initialization Process Changes
During system initialization, SAP Commerce creates the following MediaFolders by factory default:
cronjob
hmc
impex
root
Changes in Handling Media
This section discusses how the introduction of MediaFolders affects working with Medias.
This is custom documentation. For more information, please visit the SAP Help Portal
219
5/27/2022
API
The SAP Commerce getter and setter methods are not affected by the MediaFolder a media is in. Calling the MediaService getMedia( String) method, for example, returns
every media that matches the search pattern, irregardless of whether the individual media is in a MediaFolder or not.
HMC
Due to the MediaFolder functionality, an additional entry has been added to the Hybris Management Console explorer tree: Media Folder.
Working with Medias is not any different. You can work with Medias just as before. In addition, you can search for all Medias that are assigned to a speci c MediaFolder:
Related Information
Media Guide
mediaweb Extension
Initializing and Updating SAP Commerce
mediaweb Extension
The mediaweb extension has two purposes: to de ne where media les are located and to redirect HTTP and HTTPS requests to them.
Redirect Servlet:
The mediaweb extension contains a Java Servlet that evaluates the path to where the Media les are located and makes sure that HTTP and HTTPS requests are
modi ed to match that path. See Media Guide, section Media URLs.
Media File Storage Location:
The mediaweb extension is the factory default location where les of Media items are stored, such as images, CSV les, or video clips. For Cluster systems (see
Cluster), you need to specify a network share as storage location instead using the media-related properties, such as media.replication.dirs.
 Note
An SAP Commerce extension may provide functionality that is licensed through different SAP Commerce modules. Make sure to limit your implementation to the
features de ned in your contract license. In case of doubt, please contact your sales representative.
Related Information
Media Guide
Con guring the Behavior of SAP Commerce
Storing Many Files for One Media Item
Normally, a single Media item holds reference to only one le. However, you may need to have a Media item that refers to more than one le. For example, you have many
pictures of one product and you want to have only one Media item for all these pictures.
It is possible with DerivedMedia item and so called derived media functionality.
 Note
Derived media functionality is only accessible from ServiceLayer.
This is custom documentation. For more information, please visit the SAP Help Portal
220
5/27/2022
Overview
DerivedMedia item is related to Media item. It is one to many relation, it means that basically one Media object can hold a collection of DerivedMedia objects. Each
DerivedMedia holds its own binary data ( le) and unique version name. Version is just a string identi er, it could be for instance name of data format, like thumbnail or web.
Below you can see a diagram that describes the architecture:
Using API
You cannot use derived medias functionality from HMC, you can only access it through the API. You have to use MediaService.
Add Additional Stream to Media
Example:
// Imagine that you have Media model already created and MediaService injected by Spring
final MediaModel media;
final MediaService mediaService;
// And you have a stream of data
final InputStream myData;
// You can upload new version of binary data
final String versionId = "myFancyVersion";
mediaService.addVersionStreamForMedia(media, versionId, myData);
Retrieve Stream for Media in a Speci c Version:
Example:
// Imagine that you have Media model already created and MediaService injected by Spring
final MediaModel media;
final MediaService mediaService;
final String versionId = "myFancyVersion";
final InputStream stream = mediaService.getStreamForMediaVersion(media, versionId);
Get Direct URL Link for a Speci c Version:
Example:
// Imagine that you have Media model already created and MediaService injected by Spring
final MediaModel media;
final MediaService mediaService;
final String versionId = "myFancyVersion";
final String mediaURL = mediaService.getUrlForMediaVersion(media, versionId)
Remove Speci c Version from Media:
Example:
// Suppose that we have Media model already created and MediaService injected by Spring
final MediaModel media;
final MediaService mediaService;
final String versionId = "myFancyVersion";
mediaService.removeVersionForMedia(media, versionId);
This is custom documentation. For more information, please visit the SAP Help Portal
221
5/27/2022
Media Storage Overview
The concept of media storage means how and where binary data of any Media item is stored and read.
Storage can be local or can use remote services. Local storage means that binary data is stored as les in the same place where you deployed your SAP Commerce
installation. With remote service storage, you can choose between three ready-to-use implementations for Amazon S3, Windows Azure Blob, and MongoDB GridFS. Different
external storage services require different ways of communication and usage of different API or external libraries. Therefore, the architecture of media storage
implementation allows you also to create your custom media storage strategy for a variety of external services.
Overview
The UML diagram below depicts the architecture of the media storage concept. It shows all important interfaces and interdependencies:
MediaStorageStrategy: Performs actions on media data streams, like store, read and delete.
MediaURLStrategy: Renders public web URLs.
MediaStorageRegistry: Aggregates and serves all con gured MediaStorageStrategy and MediaURLStrategy objects.
MediaStorageCon gService: Keeps the con guration of each MediaFolder up to date.
LocalFileMediaCache: Caches les locally.
MediaStorageInitializer: Provides method for cleaning out media storage on fresh initialization of SAP Commerce.
MediaManager is the only connection between Media item and media storage.
Available Storing Strategies
Currently you can choose between the following storing strategies:
LocalFileMediaStorageStrategy: Responsible for storing binary data in local le system storage. It is used by default. For more details read Using Local Media
Storage Strategy.
S3MediaStorageStrategy: Responsible for storing binary data in Amazon S3. For more details read Using Amazon S3 Media Storage Strategy.
This is custom documentation. For more information, please visit the SAP Help Portal
222
5/27/2022
WindowsAzureBlobStorageStrategy: Responsible for storing binary data in Windows Azure Blob Store. For more details read Windows Azure Blob Media Storage
Strategy.
GridFSMediaStorageStrategy: Responsible for storing binary data in MongoDB. For more details read Using MongoDB GridFS Media Storage Strategy.
Con guration
Con guration for whole media storage infrastructure is based on properties and a special naming convention, which all media related properties must follow. Properties can
be divided into three priority levels, whereby a level with a higher priority overrides a setting with a lower priority level:
1. Default settings - priority 3
2. Global settings (for speci c strategy) - priority 2
3. Folder settings - priority 1
Naming Convention
All property keys must follow certain naming convention rules, which are described in the sections below. Keys contain: a xed, level-speci c pre x, a variable part, and a
suffix: a so-called subKey. Some keys also need to contain a Spring bean id of the speci c storage strategy or a folder quali er (the variable part of key, not always required).
For better readability, parts of key will be colored as follows:
pre x
variable part
subKey
Default Settings
It is possible to use the local.properties le to con gure default settings for the media infrastructure. These settings will be read in if, for example, a particular folder
does not have any media storage strategy attached: In this case the necessary strategy will be picked up from default settings. Another example is a situation where a folder
is not con gured at all: again, default settings will be used. You can see the default Commerce Platform con guration with its description in the main project.properties le.
 Note
Do Not Modify Default Settings
Do not modify the default settings unless you really know what you are doing. Default settings provide tried and tested values for the media storage infrastructure.
For more information, see Con guration Properties.
All keys in this level follow naming convention:
media.default. subKey
An example of valid default settings for Local Media Storage Strategy is:
local.properties
media.default.storage.strategy=localFileMediaStorageStrategy
media.default.secured=false
media.default.hashing.depth=2
Global Settings
Sometimes, you can use speci c global settings to activate certain strategies, for instance credentials. All keys at this level must conform to the following naming
convention:
media.globalSettings. springBeanIdOfParticularStorageStrategy. subKey
This is an example of valid global settings for the S3 Media Storage Strategy:
local.properties
media.globalSettings.s3MediaStorageStrategy.accessKeyId=123456
media.globalSettings.s3MediaStorageStrategy.secretAccessKey=foobarbaz
media.globalSettings.s3MediaStorageStrategy.hashing.depth=3
media.globalSettings.s3MediaStorageStrategy.secured=true
In the example above, the media storage strategy identi ed by the id s3MediaStorageStrategy de nes two additional subKeys: accessKeyId and secretAccessKey,
overrides two subKeys from default settings: hashing.depth with the value 3, and secured with the value true. With this con guration, all folders that are con gured to use
this strategy will be secured by default and will store data in a three-sub-folders structure.
Folder Settings
Each media folder can be con gured separately, which makes the whole con guration very exible. Bear in mind that folder-speci c settings have precedence over default or
global settings and that subKeys from default and global settings may be used in folder settings. All keys in this level must follow the naming convention:
This is custom documentation. For more information, please visit the SAP Help Portal
223
5/27/2022
media.folder. folderQuali er. subKey
An example of valid settings for a folder with the quali er foo is:
local.properties
media.folder.foo.storage.strategy=s3MediaStorageStrategy
media.folder.foo.accessKeyId=78900
media.folder.foo.secretAccessKey=bazbarfoo
media.folder.foo.hashing.depth=4
media.folder.foo.secured=false
In the example above, the folder foo is con gured to use s3MediaStorageStrategy, thus it can override its global settings. It overrides both accessKeyId and
secretAccessKey (so it may use different credentials to S3 storage). It also overrides default settings for hashing.depth with value 4 and secured with the value false.
Con gure with MediaStorageCon gService
For easy management of the media storage con guration, the Commerce Platform is shipped with the MediaStorageCon gService interface and its default implementation
DefaultMediaStorageCon gService, which can be taken from the Spring context by using mediaStorageCon gService Spring bean id. This class is the central point for
reading in the whole con guration for the media storage infrastructure.
For more information, see SAP Commerce JavaDocs
This service produces two DTO objects that can be used for reading the con guration:
MediaFolderCon g: Used in most cases, keeps all required settings for a particular folder. All folder-speci c overrides are taken into account here.
GlobalMediaStorageCon g: This object keeps global settings for the globally con gured storage strategy with the media.default.storage.strategy property.
In most cases, if you want to implement your own storage strategy, you will use the MediaFolderCon g DTO con g object, which is passed all the time as the rst parameter
to every method in the two main interfaces: MediaStorageStrategy and MediaURLStrategy.
MediaFolderConfig DTO object itself provides a set of direct methods to read values speci c to the default level of con guration:
// let's assume config object is ready to use
MediaFolderConfig config;
boolean secured = config.isSecured();
boolean cacheEnabled = config.isLocalCacheEnabled();
int hashingDepth = config.getHashingDepth();
as well as three generic methods to read any con guration subKey for its value:
// lets assume config object is ready to use
MediaFolderConfig config;
// Read plain String value
String strategyId = config.getValue("storage.strategy");
// Read Boolean value
Boolean secured = config.getValue("secured", Boolean.class);
// Read Integer value and return 10 as default when subKey has no value
Integer myValue = config.getValue("some.integer.subKey", Integer.class, Integer.valueOf(10));
and methods to read information about folder like its quali er, storage strategy bean id which is used and con gured url strategy bean Ids:
// lets assume config object is ready to use
MediaFolderConfig config;
String folderQualifier = config.getFolderQualifier();
String strategyId = config.getStorageStrategyId();
Iterable<String> urlStrategies = config.getURLStrategyIds();
 Note
Keep in mind that all keys stored in con guration DTO objects are subKeys
All values for con guration subKeys stored in DTO objects are valid Java types. Conversion from String is done by converters which are registered for the following
prede ned subKeys:
url.strategy
local.cache
secured
hashing.depth
cleanOnInit
System by default provides three converters:
IntegerValueConverter - Spring bean ID: integerCon gValueConverter. Converts string representation of integer into Integer object.
This is custom documentation. For more information, please visit the SAP Help Portal
224
5/27/2022
BooleanValueConverter - Spring bean ID: booleanCon gValueConverter. Converts string representation of boolean into Boolean object.
IterableValueConverter - Spring bean ID: iterableCon gValueConverter. Converts comma separated string of values into Iterable object containing all values as
strings.
By default all custom settings are stored without conversion. However, the user may want to use converters. It is just matter of registering bean of class
Con gValueMappingRegistrar as follows:
<bean id="someCustomSubKeyConversionMapping" class="de.hybris.platform.media.storage.impl.ConfigValueMappingRegistrar" p:key="my.fancy
p:value-ref="integerConfigValueConverter" />
Assuming that my.fancy.subKey points to an Integer value, this mapping will register it to use IntegerValueConverter.
It is also possible to write your own converters by implementing de.hybris.platform.media.storage.Con gValueConverter interface and registering it to any subKey as was
shown in example above. All registered mappings are scanned and used automatically by MediaStorageCon gService.
Storing Media Files in a Structure of Subfolders
Each of the provided storage strategies may store medias in a structure of subfolders. The name of each subfolder consists of the following:
h pre x.
Hex representation of a hash code extracted from computation of 11111111 value and each byte from hash code representation of Media 's dataPK. Logical AND
operation is used in computing.
For example, dataPK of a selected media item has the following byte representation: 00100001 00001000 00011101 10101100. By default two levels depth subfolders
structure will be created. This means that two separate AND operations are performed on rst two bytes and value 11111111:
10101100 AND 11111111 gives 10101100. Hex representation of extracted byte is AC
00011101 AND 11111111 gives 00011101. Hex representation of extracted byte is 1D
Then h pre x is added to each hex representation and in this way you get the names of each subfolder. Your media data will be stored in the following location:
${HYBRIS_DATA_DIR} media/sys_master/hac/h1d. When the le is stored in its physical location, the relative location is cached in location property of the Media item
and is used when read request for a Media comes next time. This location may look like in the following example:
sys_master/root/h44/h9a/8796157444126.jpg
This solution gives you a possibility to have 256 folders at each level. This means 65.536 folders can be created in total. If you assume that in each folder you store 1000 les,
it gives us over 65 million les in total.
To use this algorithm in a custom storage service you have to use HierarchicalMediaPathBuilder class. Here is an example:
HierarchicalMediaPathBuilder pathBuilder = HierarchicalMediaPathBuilder.forDepth(2);
final String mainFolderPath = "sys_master/root/";
final String yourMediaId = "12345678.jpg";
final String path = pathBuilder.buildPathForMedia(mainFolderPath, yourMediaId, subDirDepth);
// Now returning path looks like this: sys_master/root/hd1/hc2/h00/
Migrate to Structure of Subfolders
It is possible to migrate any folder structure after changing MediaFolder con guration. You have to do the following:
1. Create an instance of the MediaFolderStructureMigrationCronJob cron job
2. Assign it to the mediaFolderStructureMigration job
3. Provide the name of the MediaFolder that have to be migrated
4. Execute the cron job
You can do it in HMC or using code like in the following example:
// Assume you have already injected services
final ModelService modelService;
final MediaService mediaService;
final CronJobService cronJobService;
// You want to migrate root folder
final MediaFolderStructureMigrationCronJobModel cj = modelService.create(MediaFolderStructureMigrationCronJobModel.class);
cj.setMediaFolder(mediaService.getRootFolder());
// Set mediaFolderStructureMigration job which is already defined in the initialized system
cj.setJob(cronJobService.getJob("mediaFolderStructureMigration"));
modelService.save(cj);
// Perform configured CronJob
cronJobService.performCronJob(cj);
The mediaFolderStructureMigration job looks for all Media les related to your MediaFolder and moves them to proper subfolder structure. The whole process uses the
default paging strategy (100 items on each page) so even folders with a large number of les can be migrated safely.
This is custom documentation. For more information, please visit the SAP Help Portal
225
5/27/2022
Local File Caching
External storages may affect performance when requesting les, thus it is recommended to use a local le caching mechanism. Each storage strategy allows enabling of
local le caching. A general overview of the caching mechanism is shown in the picture below:
The idea of caching les locally is described below:
1. User is uploading data:
a. Data stream is locally cached as le on the local le system
b. Data stream is sent to con gured storage through storage strategy
2. User is requesting for data:
a. Local cache is requested for the data
If le exist, then stream is sent to the user
If le does not exist, then external storage is requested for the data that is cached locally and sent as stream to the user
Con gure Local File Caching
You can provide the following changes in the default con guration:
Control subdirectory name:
local.properties
media.default.local.cache.rootCacheFolder=localCache
If you like to store cache les separately for each media folder (for example when you want to store cache les on separate disks or partitions), you can do it as
follows:
local.properties
media.folder.myFolder1.local.cache.rootCacheFolder=myFolder1-cache
media.folder.myFolder2.local.cache.rootCacheFolder=myFolder2-cache
 Note
Enabling local le caching makes sense only for storing strategies that use LocalMediaWebURLStrategy.
 Caution
Declaring max cache size via media.default.local.cache.maxSize requires to declare it higher then an expected le size. Uploading le with size greater than declared
max cache size will cause an exception.
Evictions
Evictions to the cache will occur automatically but you can also evict any cached le by hand by calling:
// assuming that localMediaFileCacheService and mediaStorageConfigService are taken from Spring context
MediaFolderConfig folderConfig = mediaStorageConfigService.getConfigForFolder("folderQualifier");
This is custom documentation. For more information, please visit the SAP Help Portal
226
5/27/2022
String locationInStorage = "some/location/foo.jpg";
localMediaFileCacheService.removeFromCache(folderConfig, locationInStorage);
When eviction is done automatically underlying logic will take care about cached le removal. File will be removed only when last client will release the usage by closing
stream. One exception to this rule is when client will ask for the real File object to cached le instead of InputStream. In this case such cached le when evicted will not be
removed from the cache but special zero-bytes marker will be created in the cache directory. Such marked les will stay in the cache to next restart of the Platform and then
removed on Platform startup. It is also save to delete such les (together with marker les) directly using operating system commands. Below is example of cached le and
its eviction marker:
/h0f/h72/ODc5NjE4NzM2MTMxMC8zMDgzMS5qcGc=__H__c9690cd1-10e0-436b-9ce0-b509a5b0c721.bin
/h0f/h72/ODc5NjE4NzM2MTMxMC8zMDgzMS5qcGc=__H__c9690cd1-10e0-436b-9ce0-b509a5b0c721.bin.EVICTED
Media Location Veri cation
All media storage strategies provided by SAP Commerce compute the hash from the name of the MediaFolder, location of the Media item and a special salt string con gured
in project.properties le under media.storage.location.hash.salt property.
 Caution
Necessary Con guration for Security Reason
It is highly recommended for security reason to change hash salt property for each installation of SAP Commerce to some very unique value.
The computed hash is stored in locationHash of the Media item and is then veri ed by the MediaFilter when serving medias by the mediaweb extension. It means that this
mechanism works only when the LocalMediaWebURLStrategy is used for creating media URLs. If the MediaFilter does not verify the hash provided in request, then a
HttpServletResponse.SC_FORBIDDEN response is send.
 Note
Avoid Media Location Veri cation
You can avoid media location veri cation:
If you do not want to have this option, then you can avoid it when using S3MediaStorageStrategy and WindowsAzureBlobStorageStrategy. You just need to use
corresponding URL strategies instead of LocalMediaWebURLStrategy:
s3MediaUrlStrategy with S3MediaStorageStrategy
windowsAzureBlobURLStrategy with WindowsAzureBlobStorageStrategy
If you do not want to have this option while using your custom storage strategy, but you want to use LocalMediaWebURLStrategy as there is no need to
implement a custom URL strategy, then just do not implement a hash computation in your custom storage strategy. In this case the LocalMediaWebURLStrategy
constructs URLs with a special marker, which will bypass the veri cation procedure.
Initializing Media Storage on Initialization or Update
Each time user is executing a full initialization or update of the SAP Commerce, media storage may be initialized in a special way - for instance it can be cleaned out. Because
different kind of storages may provide different ways of initialization, mostly because of different APIs, you can use the MediaStorageInitializer interface, which contains two
methods: onInit() and onUpdate(). Any implementation of the MediaStorageInitializer is used during the initialization or update process automatically.
Creating Custom Media Storage and URL Strategy
You can create your own media storage strategy. In the simplest scenario you can just implement the MediaStorageStrategy and use the existing
LocalMediaWebURLStrategy for rendering URLs. If specially crafted URLs are needed, then the MediaURLStrategy must be implemented as well.
You can also use the following interfaces and implementations that help developing the media storage related logic:
MediaStorageInitializer: If you want to execute any logic during a fresh initialization or update, implement this interface and register in the Spring context.
Media location veri cation: Inject MediaLocationHashService into your custom MediaStorageStrategy and then use it in the storeMedia method as follows:
@Override
public StoredMediaData storeMedia(final String folderQualifier, final String mediaId, final Map<String, Object> metaData, final I
{
// Storage logic goes here. Here locationOfMedia and size should be accessible
// locationHashService should be injected by Spring
return new StoredMediaData(locationOfMedia, locationHashService.createHashForLocation(folderQualifier, locationOfMedia), size);
}
Related Information
Media Guide
Con guring the Behavior of SAP Commerce
Using Local Media Storage Strategy
This is custom documentation. For more information, please visit the SAP Help Portal
227
5/27/2022
In this strategy all data are stored locally in local le system storage de ned by media.read.dir and media.replication.dirs properties. The default con guration is that all les
for all MediaFolders use Local Storage strategy.
Con gure Local Storage Strategy
You can change default con guration by putting in local.properties le custom values for the following properties:
local.properties
media.default.storage.strategy=localFileMediaStorageStrategy
media.default.hashing.depth=2
// Where media files are written. Instead of below location you can also use '/usr/var/media' or '\\\\hostname\\shared_folder'
media.replication.dirs=c:\\media
media.read.dir=c:\\media
It is possible to mix different strategies per MediaFolder. To con gure your custom MediaFolder to store binary data of a Media item on the local le system you need to
provide custom values for set of properties in your local.properties le. Below you have an example of con guration provided for folder localMedias1:
local.properties
media.folder.localMedias1.storage.strategy=localFileMediaStorageStrategy
media.folder.localMedias1.url.strategy=localMediaWebURLStrategy
media.folder.localMedias1.hashing.depth=1
Using Amazon S3 Media Storage Strategy
Amazon S3 provides a simple web services interface that can be used to store and retrieve any amount of data. You can con gure a speci c MediaFolder to store binary data
of a Media item directly in Amazon S3.
Con guring Amazon S3 Storage Strategy
To con gure your custom MediaFolder to store binary data of a Media item in Amazon S3 you need to provide custom values for set of properties in your
local.properties le. All available properties are listed in the project.properties le of amazoncloud extension.
 Note
Amazon S3 Media Storage Strategy Con guration Preconditions
To con gure your MediaFolder to use Amazon S3 you need to have:
Amazon Web Services account
Bucket
Create access keys pair:
Access Key Id
Secret Access Key
For more details read http://aws.amazon.com/documentation/s3/
.
Assume that you want to setup newly created MediaFolder called s3medias1 to work with Amazon S3. To see how the con guration should look like for particular URL
strategy go to the following sections:
For local URL strategy: Use Local URL Strategy
For S3 URL strategy: Use S3 URL Strategy
Use Local URL Strategy
To use local URL strategy put the following properties in your local.properties le:
local.properties
// Put Spring bean id of the S3 strategy that keeps the logic responsible for communication between SAP Commerce and Amazon S3
media.folder.s3medias1.storage.strategy=s3MediaStorageStrategy
media.folder.s3medias1.accessKeyId=YourAccessKey
media.folder.s3medias1.secretAccessKey=YourSecretAccessKey
// Set up your URL strategy
media.folder.s3medias1.url.strategy=localMediaWebURLStrategy
 Note
Find Out More
This is custom documentation. For more information, please visit the SAP Help Portal
228
5/27/2022
Keep in mind that localMediaWebURLStrategy is used by default for rendering URLs but data stream is still coming directly from Amazon S3 thanks to
S3MediaStorageStrategy.
Use S3 URL Strategy
S3 URL strategy is recommended if you want to use direct URLs to Amazon S3. It renders direct URLs, signed or unsigned.
You can use S3 URL strategy, by default with signed URLs and set custom time for how long the URL is valid:
local.properties
// Put Spring bean id of the S3 strategy that keeps the logic responsible for communication between SAP Commerce and Amazon S3
media.folder.s3medias1.storage.strategy=s3MediaStorageStrategy
media.folder.s3medias1.url.strategy=s3MediaUrlStrategy
// Set that URL is valid for 5 minutes
media.folder.s3medias1.url.signed.validFor=5
media.folder.s3medias1.accessKeyId=YourAccessKey
media.folder.s3medias1.secretAccessKey=YourSecretAccessKey
If you do not want to use signed URLs then provide the following con guration:
local.properties
// Put Spring bean id of the S3 strategy that keeps the logic responsible for communication between SAP Commerce and Amazon S3
media.folder.s3medias1.storage.strategy=s3MediaStorageStrategy
media.folder.s3medias1.url.strategy=s3MediaUrlStrategy
media.folder.s3medias1.url.signed=false
media.folder.s3medias1.accessKeyId=YourAccessKey
media.folder.s3medias1.secretAccessKey=YourSecretAccessKey
All available properties are listed in the project.properties le of amazoncloud extension.
Bucket Creation
S3 Storage strategy requires providing bucketId in con guration which points to already existing and con gured bucket in S3 storage. To con gure SAP Commerce to use
such bucket use following setting:
local.properties
media.folder.s3medias1.bucketId=myBucket
To set up one global bucket for all medias:
local.properties
media.globalSettings.s3MediaStorageStrategy.bucketId=myBucket
Use More Than One URL Strategy for One MediaFolder
It is possible to bind more than one URL strategy to the MediaFolder by providing list of comma separated Spring bean ids. By default rst strategy from left is used. It is
possible to change used strategy by using local session context and by providing the Spring bean id to use for instance for one particular URL.
For example your MediaFolder is con gured like in the following example:
local.properties
media.folder.s3medias1.url.strategy=localMediaWebURLStrategy,someSpecialURLStrategy,otherUrlStrategy
You can change for a moment URL strategy in local session context like in the following code sample:
// SessionService is injected by Spring
final SessionService sessionService;
sessionService.executeInLocalView(new SessionExecutionBody()
{
@Override
public TranslationResult execute()
{
sessionService.setAttribute(MediaManager.PREFERRED_URL_STRATEGY_ID, "someSpecialURLStrategy");
// render URL here
}
});
This is custom documentation. For more information, please visit the SAP Help Portal
229
5/27/2022
Common Con guration Properties
You may con gure more than one MediaFolder with the Amazon S3 media storage strategy. To not repeat the same properties separately for every MediaFolder, you can use
global con guration properties. For example you have the following MediaFolders: s3medias1, s3medias2 and s3medias3 and you want them to work with Amazon S3 media
storage strategy. You can shorten the con guration like in the following example:
local.properties
media.globalSettings.s3MediaStorageStrategy.accessKeyId=YourAccessKey
media.globalSettings.s3MediaStorageStrategy.secretAccessKey=YourSecretAccessKey
media.globalSettings.s3MediaStorageStrategy.endpoint=endpointAddress
media.globalSettings.s3MediaStorageStrategy.url.signed=false
media.globalSettings.s3MediaStorageStrategy.url.unsigned.https=true
media.globalSettings.s3MediaStorageStrategy.url.unsigned.virtualHost=false
media.globalSettings.s3MediaStorageStrategy.url.validFor=120
media.folder.s3medias1.storage.strategy=s3MediaStorageStrategy
media.folder.s3medias1.url.strategy=localMediaWebURLStrategy
media.folder.s3medias2.storage.strategy=s3MediaStorageStrategy
media.folder.s3medias2.url.strategy=localMediaWebURLStrategy
media.folder.s3medias3.storage.strategy=s3MediaStorageStrategy
media.folder.s3medias3.url.strategy=localMediaWebURLStrategy
To control cleaning S3 storage on fresh initialization of Commerce Platform use following global property:
local.properties
media.globalSettings.s3MediaStorageStrategy.cleanOnInit=true
For more information, see Media Storage Overview, section Cleaning Media Storage on Initialization.
You can nd the list of all available common con guration properties in the project.properties le of amazoncloud extension.
Cache Setting for a Speci c mediaFolder
If you want to use S3-Integration for a speci c mediaFolder and your system doesn't work properly with the default <media.default.local.cache.rootCacheFolder=cache>
property setting, you can explicitly set this property to apply for S3-Integration on that level:
media.folder.s3medias1.storage.strategy=s3MediaStorageStrategy
media.folder.s3medias1.url.strategy=localMediaWebURLStrategy
media.folder.s3medias1.local.cache.rootCacheFolder=custom
Related Information
http://aws.amazon.com/
Using MongoDB GridFS Media Storage Strategy
MongoDB database provides speci cation for storing large les called GridFS. You can con gure a speci c MediaFolder to store binary data of a Media item directly in
MongoDB.
Con guring MongoDB GridFS Storage Strategy
To con gure your custom MediaFolder to store binary data of a Media item in MongoDB you need to provide custom values for set of properties in your
local.properties le. All available properties are listed in the project.properties le of gridfsstorage extension.
 Note
MongoDB GridFS Media Storage Strategy Con guration Preconditions
To con gure your MediaFolder to use MongoDB you need to have up and running MongoDB server. For more details read http://www.mongodb.org/display/DOCS/Home
.
Assume that you want to setup newly created MediaFolder called mongoFiles to work with MongoDB. You need to provide the following con guration:
local.properties
media.globalSettings.gridFsStorageStrategy.mongo.host=localhost
media.globalSettings.gridFsStorageStrategy.mongo.port=27017
media.globalSettings.gridFsStorageStrategy.mongo.dbname=hybris_storage
media.globalSettings.gridFsStorageStrategy.mongo.username=mongoDbUserName
media.globalSettings.gridFsStorageStrategy.mongo.password=mongoDbSecret
This is custom documentation. For more information, please visit the SAP Help Portal
230
5/27/2022
// Put Spring bean id of the GridFS storage strategy that keeps the logic responsible for communication between SAP Commerce and Mongo
media.folder.mongoFiles.storage.strategy=gridFsStorageStrategy
 Note
Find Out More
Keep in mind that localMediaWebURLStrategy is used by default for rendering URLs but data stream is still coming directly from MongoDB thanks to
GridFSMediaStorageStrategy.
Automatic Bucket Creation
By default MongoDB GridFS Storage strategy provides automatic bucket creation. Bucket name is computed from current tenantId and from the name of used MediaFolder.
For instance if current tenantId is master and MediaFolder name is root, then created bucket name is sys_master_root. If you like to override this behavior for custom folder
you can use con guration property:
local.properties
media.folder.mongoFiles.bucketId=myBucket
To set up one global bucket for all medias:
local.properties
media.globalSettings.gridFsStorageStrategy.bucketId=myBucket
 Tip
Current tenantId Pre x is Always Added
Keep in mind that even if name of custom bucket is myBucket, then pre x with tenantId is added automatically, so nally bucket name is sys_master_myBucket. The
pattern is sys_<tenantID>_<bucketName>.
Use More Then One URL Strategy for One MediaFolder
It is possible to bind more than one URL strategy to the MediaFolder by providing list of comma separated Spring bean ids. By default rst strategy from left is used. It is
possible to change used strategy by using local session context and by providing the Spring bean id to use for instance for one particular URL. However gridfsstorage
extensions does not provide special MongoDB related strategy. You can create your own URL strategy. For more details read Media Storage Overview, section Creating
Custom Media Storage and URL Strategy For example your MediaFolder is con gured like in the following example:
local.properties
folder.mongoFiles.url.strategy=localMediaWebURLStrategy,someSpecialURLStrategy,otherUrlStrategy
You can change for a moment URL strategy in local session context like in the following code sample:
// SessionService is injected by Spring
final SessionService sessionService;
sessionService.executeInLocalView(new SessionExecutionBody()
{
@Override
public TranslationResult execute()
{
sessionService.setAttribute(MediaManager.PREFERRED_URL_STRATEGY_ID, "someSpecialURLStrategy");
// render URL here
}
});
Common Con guration Properties
You may con gure more than one MediaFolder with the MongoDB GridFS media storage strategy. To not repeat the same properties separately for every MediaFolder, you
can use global con guration properties. For example you have the following MediaFolders: mongoFiles1, mongoFiles2 and mongoFiles3 and you want them to work with
MongoDB GridFS media storage strategy with the same bucket ID. You can shorten the con guration like in the following example:
local.properties
media.globalSettings.gridFsStorageStrategy.bucketId=mySpecialBucket
folder.mongoFiles1.storage.strategy=gridFsStorageStrategy
folder.mongoFiles2.storage.strategy=gridFsStorageStrategy
folder.mongoFiles3.storage.strategy=gridFsStorageStrategy
This is custom documentation. For more information, please visit the SAP Help Portal
231
5/27/2022
To control cleaning MongoDB GridFS storage on fresh initialization of Commerce Platform use following global property:
local.properties
media.globalSettings.gridFsStorageStrategy.cleanOnInit=true
For more information, see Media Storage Overview, section Cleaning Media Storage on Initialization.
You can nd the list of all available common con guration properties in the project.properties le of gridfsstorage extension.
Related Information
http://www.mongodb.org/
Windows Azure Blob Media Storage Strategy
Windows Azure Blob provides a simple web services interface that can be used to store and retrieve any amount of data. You can con gure a speci c MediaFolder to store
binary data of a Media item directly in Windows Azure Blob.
To con gure your custom MediaFolder to store binary data of a Media item in Windows Azure Blob you need to provide custom values for set of properties in your
local.properties le. All available properties are listed in the project.properties le of azurecloud extension.
 Note
Windows Azure Media Storage Strategy Con guration Preconditions
To con gure your folder to use Windows Azure Blob you need to have:
Windows Azure account
Properly created Access Keys
For more details read http://www.windowsazure.com/en-us/develop/net/how-to-guides/blob-storage/
.
Assume that you want to setup newly created MediaFolder called azureMedias1 to work with Windows Azure Blob and your container called test_container. You need to
provide the following con guration:
local.properties
media.folder.azureMedias1.storage.strategy=windowsAzureBlobStorageStrategy
media.folder.azureMedias1.connection=DefaultEndpointsProtocol=http;AccountName=yourAccountName;AccountKey=yourAccountKey
media.folder.azureMedias1.public.base.url=publicBaseURL
media.folder.azureMedias1.containerAddress=test_container
 Note
Find Out More
Keep in mind that localMediaWebURLStrategy is used by default for rendering URLs but data stream is still coming directly from Windows Azure Blob thanks to
WindowsAzureBlobStorageStrategy.
If you would like to use direct URLs to Windows Azure Blob, then you can use another URL strategy called windowsAzureBlobURLStrategy that is responsible to render direct
URLs to medias. Below you have an example of direct URL to speci c Media item:
http://hybrisazure.blob.core.windows.net/hybris/sys_master/root/h3e/hd7/8796157378590.jpg
 Note
Local File Caching
At the moment Windows Azure Blob storage strategy requires local le caching to work properly, thus folder have to be con gured to support caching:
media.folder.azureMedias1.local.cache=true
or global setting for strategy must be set:
media.globalSettings.windowsAzureBlobStorageStrategy.local.cache=true
For more details read Media Storage, section Local File Caching. If local caching will not be enabled following exception will be thrown during storing attempt:
java.lang.IllegalArgumentException: Object size as Long is required to store blobs in Azure Blob Storage. Only local caching allows
Known Issues
This is custom documentation. For more information, please visit the SAP Help Portal
232
5/27/2022
You may get an error if you don't set the caching folder value for the media.folder.<folderName>.local.cache.rootCacheFolder property explicitly. Here is
an example error log:
[java] ERROR [main] [MediaCacheRecreator] Cannot decode original location from cached file name: 8796093415454.txt
[java] ERROR [main] [MediaCacheRecreator] Cannot decode original location from cached file name: 8796093349918.txt
[java] ERROR [main] [MediaCacheRecreator] Cannot decode original location from cached file name: 8796094038046.bin
To remedy this, explicitly set up the appropriate value for the media.folder.<folderName>.local.cache.rootCacheFolder property, for example:
media.folder.azureMedias1.local.cache.rootCacheFolder=${media.default.local.cache.rootCacheFolder}
Automatic Container Creation
By default Windows Azure strategy provides automatic container creation. Container name is computed from current tenantId and from the name of used MediaFolder. For
instance if current tenantId is master and MediaFolder name is root, then created container name is sys-master-root. If you like to override this behavior for custom folder
you can use the following property:
local.properties
media.folder.azureMedias1.containerAddress=myContainer
To set up one global container for all medias:
local.properties
media.globalSettings.windowsAzureBlobStorageStrategy.containerAddress=myContainer
 Tip
Current tenantId Pre x is Always Added
Keep in mind that even if name of custom container is myContainer, then pre x with tenantId is added automatically, so nally container name is sys-mastermyContainer. The pattern is sys-<tenantID>-<containerName>.
Use More Than One URL Strategy for One MediaFolder
It is possible to bind more than one URL strategy to the MediaFolder by providing list of comma separated Spring bean ids. By default rst strategy from left is used. It is
possible to change used strategy by using local session context and by providing the Spring bean id to use for instance for one particular URL.
For example your MediaFolder is con gured like in the following example:
local.properties
media.folder.azureMedias1.url.strategy=localMediaWebURLStrategy,someSpecialURLStrategy,otherUrlStrategy
You can change for a moment URL strategy in local session context like in the following code sample:
// SessionService is injected by Spring
final SessionService sessionService;
sessionService.executeInLocalView(new SessionExecutionBody()
{
@Override
public TranslationResult execute()
{
sessionService.setAttribute(MediaManager.PREFERRED_URL_STRATEGY_ID, "someSpecialURLStrategy");
// render URL here
}
});
Common Con guration Properties
You may con gure more than one MediaFolder with the Windows Azure Blob media storage strategy. To not repeat the same properties separately for every MediaFolder,
you can use common con guration properties. For example you have the following MediaFolders: azureMedias1, azureMedias2 and azureMedias3 and you want them to work
with Windows Azure Blob media storage strategy. You can shorten the con guration like in the following example:
local.properties
media.globalSettings.windowsAzureBlobStorageStrategy.connection=DefaultEndpointsProtocol=http;AccountName=yourAccountName;AccountKey=y
media.globalSettings.windowsAzureBlobStorageStrategy.public.base.url=publicBaseURL
media.globalSettings.windowsAzureBlobStorageStrategy.containerAddress=myContainer
media.globalSettings.windowsAzureBlobStorageStrategy.local.cache=true
media.folder.azureMedias1.storage.strategy=windowsAzureBlobStorageStrategy
This is custom documentation. For more information, please visit the SAP Help Portal
233
5/27/2022
media.folder.azureMedias2.storage.strategy=windowsAzureBlobStorageStrategy
media.folder.azureMedias3.storage.strategy=windowsAzureBlobStorageStrategy
To control cleaning Windows Azure storage on fresh initialization use following global property:
local.properties
media.globalSettings.windowsAzureBlobStorageStrategy.cleanOnInit=true
For more information, see Media Storage Overview, section Cleaning Media Storage on Initialization.
You can nd the list of all available common con guration properties in the project.properties le of azurecloud extension.
Related Information
http://www.windowsazure.com
Secure Media Access
Secure media access means giving access to media after checking permissions. In other words, you cannot access speci c media by just guessing its URL. Permission check
while accessing medias is ensured by a special lter, which you can add to your custom Web application.
Overview
Secure access to a media is ensured by checking the access rights, which means that you cannot access the media by just guessing its URL. Secured media follows a
different URL pattern than unsecured media. This URL pattern can be customized to some extent, for more details read Media Guide. Checking access rights is ensured be a
special lter that is responsible for checking with the media permission service if access is granted and:
If access is granted, you receive the Media item
If access is denied, you receive a response that access is forbidden
It is possible because each Media item has its own access control list and can store access rights for any principal.
Figure: Comparison between secured and not secured access to a *Media* item.
Keep in mind that the SecureMediaFilter is in every Web application in SAP Commerce and you can also add it to your custom Web application as part of the
PlatformFilterChain, for more details read Adding SecureMediaFilter to Custom Web Application. Similarly, the MediaFilter is always a part of a separate Web application
This is custom documentation. For more information, please visit the SAP Help Portal
234
5/27/2022
that is a part of the mediaweb extension.
It is ensured that the right lter starts processing the request for a Media item by:
Having different URL patterns for secured and unsecured Media items. In other words, MediaFilter will not react to secured URLs.
Checking if the Media item belongs to a folder which is enabled for secure media access.
Enabling Secure Media Access
You can enable secure media access for speci c Media folder by putting in your local.properties le the following property set to true:
local.properties
media.folder.<folderName>.secured=true
It means that only secure URL will be rendered for each Media item stored in these folders. It also means that access to these medias will be ltered only by the
SecureMediaFilter.
Adding SecureMediaFilter to Custom Web Application
The SecureMediaFilter should be used as a part of PlatformFilterChain. It means that to start using this lter, you need to create a lter chain in your Web application. For
instructions on how to do it read hybris Platform Filters, section Con guring Existing Filters. Below you can nd an example of how the SecureMediaFilter is added to the
existing lter chain it the mam extension:
mam-web-spring.xml
<bean id="mamFilterChain" class="de.hybris.platform.servicelayer.web.PlatformFilterChain">
<constructor-arg>
<list>
<ref bean="mamRedirectFilter"/>
<ref bean="sessionFilter"/>
<ref bean="mamDataSourceSwitchingFilter"/>
<ref bean="mamCatalogVersionActivationFilter"/>
<!-- Add reference to SecureMediaFilter -->
<ref bean="mamSecureMediaFilter"/>
</list>
</constructor-arg>
</bean>
<!-- Add bean declaration for SecureMediaFilter -->
<bean id="mamSecureMediaFilter" class="de.hybris.platform.servicelayer.web.SecureMediaFilter">
<property name="mediaPermissionService" ref="mediaPermissionService"/>
<property name="modelService" ref="modelService"/>
<property name="userService" ref="userService"/>
<property name="mediaService" ref="mediaService"/>
<!-- <property name="secureMediaToken" value="securemedias"/> Change the value and remove
comment to have different prefix for secure URL -->
<aop:scoped-proxy/>
</bean>
Managing Permissions
Managing permissions for Media items is basing on the existing permission services for managing and checking access rights. For more details, read Managing and Checking
Access Rights. It is possible to set permission not only for a type but also for a speci c item. If no permission is set for a speci c item, the item's type level is checked instead.
You can manage these permissions using the following:
API: For details read Using API section.
ImpEx: For details read Using ImpEx section.
Using API
Use the MediaPermissionService for the following tasks:
Checking if the access to a Media item is granted or denied for a given principal:
// Assume you already have the following objects
MediaModel media;
UserModel user; // Can be for example fetched with userService.getCurrentUser()
//Check if given user is permitted to read the given *Media* item
boolean isGranted = mediaPermissionService.isReadAccessGranted(media, user);
Granting or denying access to a Media item for a given principal.
// Assume you already have the following objects
MediaModel media;
This is custom documentation. For more information, please visit the SAP Help Portal
235
5/27/2022
UserModel user; // Can be for example fetched with userService.getCurrentUser()
//Grant the read permission for a user on a given *Media* item
mediaPermissionService.grantReadPermission(media, user);
//Deny the read permission for a user on a given *Media* item
mediaPermissionService.denyReadPermission(media, user);
 Note
Grant and Deny Permission for a User on a Given Media Item
The principal cannot have grant and deny permissions assigned to the same Media item at the same time. The deny permission overrides the grant permission.
Using hMC
You can grant or deny access to a Media item for a give principal by opening speci c Media item and going to Security tab.
Using ImpEx
Below you can nd the example of an ImpEx import script for granting access to a Media item with code 1017895.jpg for the editor principal:
INSERT_UPDATE media; code[unique=true]; catalogVersion(catalog(id),version)[unique=true]; permittedPrincipals(uid);
;1017895.jpg; clothescatalog:Staged;editor;
 Note
Following the example above, if some other principal already had access to 1017895.jpg Media item, then this import would replace him with editor principal. In other
words, the list of principals provided in the script is not a list of principals that will be added to existing ones, but a target list of principals that should have access.
Related Information
Media Guide
hybris Platform Filters
Users in the hybris Platform
Managing and Checking Access Rights
Securing MediaFilter
The media.allowed.extensions.for.ClassLoader property enables you to explicitly specify extensions of les that you allow MediaFilter to serve from the
Commerce Platform classpath. Use this property to prevent MediaFilter from serving les you think users shouldn't have access to.
MediaFilter can serve les from the Commerce Platform classpath. The resource paths that point to such les start with the /fromjar/ url segment and are loaded by the
classloader. While useful in certain scenarios, this feature could possibly allow users to download les that they shouldn't have access to.
You can specify the types of les that can be loaded from the classpath by setting the media.allowed.extensions.for.ClassLoader property. This property expects
a coma separated list of le extensions that MediaFilter will be able to load (and serve) with the classloader:
# default settings
media.allowed.extensions.for.ClassLoader=jpeg,jpg,gif,bmp,tiff,vcard,templ,tif,csv,eps,pdf,png
# completely disabled
media.allowed.extensions.for.ClassLoader=
To make sure that, for example, no essentialdata.csv can be downloaded, exclude the csv extension from the list:
media.allowed.extensions.for.ClassLoader=jpeg,jpg,gif,bmp,tiff,vcard,templ,tif,eps,pdf,png
Now no csv les can be served from the classpath by MediaFilter.
This is custom documentation. For more information, please visit the SAP Help Portal
236
Download