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&amp;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&amp;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&amp;users_sort=uid+asc&amp; 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