Web Services
Salesforce B2C Commerce provides a web service framework, which helps you manage calls to web services and analyze service performance. The framework enforces limits that you configure ― limits on the overall number of calls allowed in a time interval, and limits on the number of failed calls allowed in a time interval. It also collects analytics on your web service calls.
For each web service, the framework requires a service configuration, a service profile configuration, and a service credential configuration. You create these configurations in Business Manager.
The service configuration generates a ServiceConfig
object. The service credential is used for basic authentication. The service profile determines how B2C Commerce manages timeouts and rate limits for the web service.
The Web Service Script
A web service script obtains a Service
object by calling the LocalServiceRegistry.createService
method. The method takes two arguments: the name of a service configuration, and a script object that contains callback code that you provide.
Your script then invokes the service by calling Service.call
. When you call this method, the framework checks if the configured rate limit or circuit breaker limit has been exceeded. If not, the framework executes the callbacks you implemented in the Service object.
When the call is complete, your script either passes the result of the successful call to the pipeline dictionary or throws an error.
If your storefront uses pipelines to call web services, the web service script is invoked by a script node within the pipeline. If your storefront uses SFRA controllers to call web services, the web service script doesn’t have to be a separate script file: it can be embedded in the controller itself.
To create a web service:
- Configure Web Services in Business Manager
- Code Your Web Service.
- Set Up Logging and Troubleshoot Your Web Service.
- Get the web service ready to go live.
- Configure credentials, private keys and certificates on the Development and Production instance. These can't be imported or exported and must be manually created on each instance.
- Use code replication to push your code to the Development and Production instance.
- Select Administration > Operations > Import & Export > Service. Select the Service option to export your service, profile, and credential configurations and import them into the Development and Production instances.
If you experience reports of problems with a specific web service on your site, in addition to logging, you can also investigate the incident using the analytics for registered web services.
The analytics are available at Business Manager: Administration > Operations > Service Status.
Click any web service name to drill down to see information about the performance of that web service. Data for a web service is available in near real time. Data is stored for up to 10 days.
Use Business Manager to configure a web service.
The web service profile defines how B2C Commerce detects and manages high numbers of requests to and responses from the service, as well as its availability. Different services with similar requirements can all use the same service profile.
-
Select Administration > Operations > Services.
-
On the Services page, click the Profiles tab.
-
On the Service Profiles page, click New.
-
On the New Service Profile page, enter a descriptive name for the profile.
-
Enter the number of milliseconds for the client connection timeout. B2C Commerce waits this number of milliseconds for a response from the web service before throwing an error.
-
Check the Enable Circuit Breaker box if you want to enable the circuit breaker to identify when a service is unavailable and stop making calls to the web service.
By default, the Enable Circuit Breaker box is checked.
We recommend that you always enable the circuit breaker, and configure it according to the service call rate.
-
(Optional) Enter the number of calls that must fail to trigger the circuit breaker into the Max Circuit Breaker Calls field.
This provides an extra level of protection on top of the default behavior provided by enabling the circuit breaker. If you set a value for this field, you must also set a value for the Circuit Breaker Interval (ms) field. Otherwise, leave both fields empty.
-
(Optional) Enter the number of milliseconds in which the maximum number of calls can fail into the Circuit Breaker Interval (ms) field.
If you set a value for this field, you must also set a value for the Max Circuit Breaker Calls field. Otherwise, leave both fields empty.
-
Check the Enable Rate Limit box if you want to limit the number of outgoing calls within a specific interval.
-
Enter the maximum number of calls that B2C Commerce makes for the rate limit interval into the Max Rate Limit Calls field.
-
Enter the number of milliseconds in which B2C Commerce can make the maximum number of calls to the web service into the Rate Limit Interval (ms) field.
The web service credentials are used for basic authentication.
-
Select Administration > Operations > Services.
-
On the Services page, click the Credentials tab.
-
On the Service Credentials page, click New.
-
On the New Service Credential page, enter a name for the credential. This name can't contain spaces. Use a descriptive name, but don’t include user or password information. For example:
http.mysite.myservice.cred
. -
Enter the URL to the service, including the protocol. For example:
ftp://51.134.145.10
To use one service configuration for several URIs, you can extend or alter this URL using the getURL callback in the service registry definition.
-
Enter the username for the credential.
-
Enter the password. The password is masked after you type it and can't be retrieved from the Business Manager, so be sure to store the value securely elsewhere.
The web service configuration specifies the credentials and web service profile that B2C Commerce uses when calling a web service.
-
Select Administration > Operations > Services.
-
On the Services page, click New.
-
On the New Service page, enter a name for the service.
We recommend the naming pattern
{cartridge}.{protocol}.{service}.{operation}
.For example:
mycartridge.http.payment.get
ormycartridge.ftp.partner.getPriceList
.If service names contain periods, the period-delimited name segments become part of the logging hierarchy. Including the cartridge in the name is useful when you have multiple web service integrations, because it groups logging information and ensures unique service names.
-
Select the service type to use for your web service. The type determines the underlying class used to call your web service and adds methods to the methods inherited from the Service class.
-
If the web service is available and you want to make calls to it, select Enabled. It isn't enabled by default.
-
In the Service Mode list, to make calls to a live web service, select Live. To use the mocked call configured in your service registry to simulate the expected response from the web service, select Mocked.
-
Enter the name of a prefix for the log file for this service.
If you don't enter a prefix, the log name defaults to
main
. All logs are written in the shared log directory to a file namedservice-prefix-internalID-date.log
. If you don’t enter a prefix, the file is namedservice-main-serviceID-date
. -
If you want data in the request and response of the web service call to be logged, select Communication Log Enabled .
If you enable the communications log, Salesforce strongly recommends using the log filtering callback methods to remove private or sensitive data from the log messages.
-
If you want to prevent unfiltered communication logs from being written on non-production instances, select Force PRD behavior in non-PRD environments.
If you enable this setting on a non-production instance, communication logs are disallowed unless a filter is configured. If you disable this setting on a non-production instance, communication logs are allowed regardless of whether a filter is configured. This setting has no effect on production instances.
-
Select one of the service profiles.
-
Select one of the service credentials.
Specify the timeout in milliseconds. This value is used for both the connection and socket timeout of any internal connection. If B2C Commerce receives no response within this time, it throws an error.
The total run time of a service can be longer than the timeout, as long as individual responses don't exceed it. For example, consider a 5000-ms timeout. A 4-second connection attempt, followed by reading two chunks of data at 4 seconds apiece, takes about 13 seconds total. Because none of the individual communications exceeded 5 seconds, the process doesn’t time out.
You can customize web service configurations, credentials, and profiles by adding custom attributes to their system objects. When added to an attribute group, these custom attributes can be edited in Business Manager.
-
Select Administration > Site Development > System Object Types.
-
On the System Object Type List page, select ServiceConfig, ServiceCredential, or ServiceProfile.
-
On the System Object Type List page, click the Attribute Definitions tab.
If you’ve already created a custom attribute, you can find and add it, otherwise, proceed to the next step.
-
On the System Object Type List page Attribute Definitions tab, click New.
-
Enter the properties for the custom attribute and click Apply.
These attributes are created identically to any other custom attributes.
-
Click << Back.
-
Click the Attribute Grouping tab.
-
On the System Object Type List page Attribute Groupings tab, click Edit for the section on the tab where you want to add your attributes.
You must add the attribute to a grouping to see it in Business Manager.
-
Click
to browse for the custom attribute you created, check its checkbox, and click Select.
When creating a web service configuration in Business Manager, you must select a service type. The type determines the underlying class used to call your web service and adds methods to those inherited from the Service class.
-
HTTP - uses
dw.net.HTTPClient
.Has additional methods to set authentication, encoding, output file, request method (defaults to POST), an HTTP header, and additional parameters for the URI.
The
parseResponse
method gives theHTTPClient
as its extra argument. -
HTTP Form - uses
dw.net.HTTPClient
.The createRequest method takes the parameters given to call() and construct a URL encoded form POST by default.
Has the same additional methods as the HTTP type, allowing you to set authentication, encoding, output file, request method (defaults to POST), an HTTP header, and additional parameters for the URI.
As with the HTTP type, the
parseResponse
method gives theHTTPClient
as its extra argument. -
FTP - uses
dw.net.FTPClient
.Has a
setOperation(String, Object...)
method to set the operation to perform when executing the call to the web service. If thesetOperation
method isn't called, the execute callback defined in the web service registry is executed when the web service is called. The callback can define any number of operations to perform.The
parseResponse
method gives the output of the method call specified bysetOperation
, or whatever object was returned by the custom execute callback. -
SFTP - uses
dw.net.SFTPClient
. It’s otherwise identical to theFTP
type. -
SOAP - uses
dw.ws.webReference2
.Requires additional methods to get the port
-
Generic - Doesn’t wrap any class. Used to define custom calls.
The rate limiter and circuit breaker determine how many calls can be made to a web service.
The rate limiter allows a maximum number of calls to a web service in a specified time interval. The rate limit is checked prior to every invocation of the web service. If the rate limit is reached, a ServiceUnavailableException
is thrown.
The timeout behavior for the rate limiter is similar to the circuit breaker timeout behavior.
The circuit breaker suspends calls to a web service if a certain number of calls fail within a specified time interval.
You can enable a circuit breaker for any service. The circuit breaker checks whether the limit of failed calls is reached prior to every invocation of the web service. If the limit is reached, B2C Commerce throws a ServiceUnavailableException
rather than execute the service. Otherwise, B2C Commerce calls the web service as usual.
If the web service fails due to something detected as a misconfiguration or remote problem, then the circuit breaker is notified. These problems include:
- Issues at initial connection:
- Unknown host
- Connection timeout
- Connection refused
- Protocol-specific errors, such as HTTP 500 - internal server error or HTTP 503 - service unavailable.
- Exceptions explicitly thrown as part of the service call
This list doesn't include HTTP 4xx errors. These are used to indicate the client is doing something wrong, but the remote server itself is fine. Assuming whatever underlying issue is causing problems is addressed, service calls return to normal as the circuit breaker timeouts expire.
Circuit Breaker Timeout Behavior
The timeout caused when the circuit breaker reaches its limit is calculated dynamically. Each time a registered web service wrapper is called, the circuit breaker is checked. If the circuit breaker is triggered, then the call isn't made. In the example below, a web service is triggered every millisecond. In this example, the circuit breaker is configured with a maximum of three failed calls per 6 milliseconds.
A service instance is a single-use object used to call a remote web service.
You can use the dw.svc.LocalServiceRegistry.createService()
method to create a service instance. This method takes two arguments:
- The ID of a service configured in Business Manager
- A configuration object with callback handlers that you implement
The callbacks contain code that is executed at appropriate times by the service framework. For example, an HTTP or FTP service instance typically implements three callbacks: createRequest
, parseResponse
, and (for testing) mockCall
.
A SOAP service implements two more callbacks: initServiceClient
and execute
.
The following FTP service instance executes a single FTP operation (list):
When you use dw.svc.Service.call(Object...)
to invoke a web service, the service framework checks whether the call exceeds either the rate limiter or circuit breaker thresholds and, if not, makes the call. When making a call, the framework invokes the callbacks you implemented in your service instance.
Each callback corresponds to one of the callback methods defined by the dw.svc.ServiceCallback
class. These methods are called in the following order:
initServiceClient(Service)
― Creates the underlying client used to make the call. Required only for SOAP Services. Other client types are created automatically.createRequest(Service, Object...)
― Given arguments to theService.call(Object...)
, configure the actual service request. This may include setting request headers, defining the message body, and so on.execute(Service, Object)
― Perform the actual request. At this point the client has been configured with the relevant credentials, so the call should be made. This is required for SOAP services.parseResponse(Service, Object)
― Convert the result of the call into an object to be returned from theService.call(Object...)
method.
Some callback methods may be optional, depending on the type of service.
Every callback method requires a Service
object (for a generic service) or one of its subclasses (FTPService
, HTTPFormService
, HTTPService
, or SOAPService
).
For an HTTP service, pass in HTTPService
objects. For an HTTP form, pass in HTTPFormService
objects.
Recommended callbacks for HTTP services:
createRequest
: Required to create arequestData
object. If you need additional processing, you can pass therequestData
object to theexecute
callback. Otherwise, therequestData
object is used to call the web service when theService
object is invoked.parseResponse
: Gives theHTTPClient
as its extra argument. Use to parse the response contained in theService
object.
For an FTP or SFTP service, pass in FTPService
objects.
Recommended callbacks
createRequest
: Required to create arequestData
object. If you need additional processing, you can pass therequestData
object to the execute callback. Otherwise, therequestData
object is used to call the web service when theService
object is called.parseResponse
: Gives theFTPClient
as its extra argument. Use to parse the response contained in theService
object.execute
: If thesetOperation
method isn't called in the web service script, operations defined in the execute callback are executed when the web service is invoked. You can use the execute method to perform multiple operations in sequence.
For any SOAP service, pass in a SOAPService
object.
Recommended callbacks
-
initServiceClient
: Implement to return adw.ws.port
andwebreferences2
object. -
createRequest
: Required to create arequestData
object. This object must be passed to the execute method. -
execute
: Specifies additional processing for the web service request.If you get your port in this step, instead of in the
initServiceClient
callback, any timeouts you set will override those set in the service configuration. This isn't recommended. -
parseResponse
: Use this method to parse the response in theService
object.
Doesn’t wrap any class. Used to define custom calls.
createRequest:
Required to create arequestData
object. If you need additional processing, you can pass therequestData
object to the execute callback. Otherwise, therequestData
object is used to call the web service when theService
object is called.- parseResponse: Use to parse the response contained in the
Service
object.
You must pass a plain Service object, rather than a subclass, for this callback method.
You can mock web service responses in two ways.
First, you can the web service to use mock responses:
- In Business Manager, select Administration > Operations > Services. For the Service Mode, select Mocked.
- Provide a
mockCall
callback handler. For example, in your web service script:
Second, you can force a mock call, regardless of configuration. Add a mock method to your service definition and then call it explicitly in your web service script. Remove this method from your script when testing live web service calls.
The general approach to coding web services in Salesforce B2C Commerce involves writing a script for a RESTful web service and storing credentials or certificates in the Business Manager.
The web service script:
- gets
Service
objects from the registry - provides input parameters for the
createRequest
callback used to construct the URL to call the web service - provides error handling based on the
Result
of the web service call - writes output variables to the pipeline dictionary to be used by the rendering template
If you’re implementing a SOAP web service or require WS-Security features, you can also write a script that uses the dw.ws
package to implement web services. In this case, certificates must be stored in your cartridge.
When creating a controller for web services, you usually must include error handling and render the results of the web service call.
If you’re maintaining an older cartridge that uses pipelines, web services are implemented in a pipeline with a script node for the web service script. The script node must have an error transition for error handling and a transition to a rendering template if you must render the results of the web service call.
Your web service script must import the dw.svc
package.
Use LocalServiceRegistry.createService
to create a Service
object. Your script can modify or extend the Service
object. You can also include business logic to control the parameters used to invoke the web service.
Use Service.call
to invoke the web service.
When the service is invoked, the service framework checks the circuit breaker and rate limiter. If either the circuit breaker or rate limiter are triggered, then no call is made and the appropriate errors are logged. If neither are triggered, then the callback methods in the service instance are executed, and the dw.svc.Result
object is stored in the Service
.
Example 1: Simple FTP Service Call
In this example, the operation invoked for the web service is determined by an input variable passed from the pipeline. In the dictionary bindings for the script node, the numCalls
variable is bound to CurrentHttpParameterMap.numCalls.stringValue
and the testType
variable is bound to CurrentHttpParameterMap.testType.stringValue
.
Example 2: Modifying the Service Object for an HTTP Service
This example demonstrates how you can use the methods on the Service
object to modify the Service
object before invoking the service. The ENCODING case in this example adds a header, URL parameters, and changes the encoding before invoking the service.
Information on the service status is stored in the Result object. Use methods on the object to determine the status of the service and any error it has returned:
result.error
- service-type specific error code, such as a 404 for an HTTP service.result.errorMessage
- error message information, such as a Java exception
You can also call .setThrowOnError when calling the service to throw a JavaScript error if the result status isn’t OK:
The service framework wraps most functionality of the underlying clients (FTPClient, HTTPClient, and so on), but you can directly configure the underlying clients when needed.
For example, if you want to cache web service calls for HTTPService
, in your createRequest
callback, use the getClient
method to get the underlying HTTPClient
object for the service and use the HTTPClient
class enableCaching
method to cache the request.
Make sure to use getClient and any HTTPClient methods in the createRequest callback or later callbacks, not when you get the service object from the registry. This is because the underlying HTTPclient object isn't initialized until you call the service using the createRequest object. Before calling the service, using getClient only returns null.
Cached requests are seen in the dashboard and you should see lower average execution times after caching is enabled. Cached requests are counted toward rate limits, circuit breakers, and statistics, because all of these are measured at the service level and are triggered by calls to the service.
You can view generated logs by navigating in Business Manager to Administration > Site Development and clicking the link for Log files.
The log file name for a web service always starts with "service" then the log prefix set in the web service profile, and then internal information. For example: service-logprefix-blade2-4-appserver-20150206.log.
Salesforce B2C Commerce logs messages to a custom log category with the following format:
Type is one of the following:
-
head: After every service call, logs a message indicating success or failure.
-
comm: After every service call, logs data passed to the underlying transport and the response received from it. Communication logs are disabled by default and log at the INFO level when enabled. This means in order to see communication logs, a service must have its Communication Log Enabled box checked and its log level must be
info
ordebug
.The comm logging is filtered to prevent sensitive data from being accidentally logged on a Production instance. The logging of filtered data is possible, but only by enabling communication logging for the service and also applying the
filterLogMessage
function or applying both thegetRequestLogMessage
andgetResponseLogMessage
functions in the service initialization. Importing a service definition with communication logging enabled on a Production system doesn't enable this logging and throws a warning message in the import log indicating that communication logging is disabled. This is a fail-safe to prevent accidentally enabling communication logging that could contain sensitive data. You can force non-production instances to behave like production instances by checking the Force PRD behavior in non-PRD environments box. -
log: Logs miscellaneous messages, such as service initialization and error traces
For example, given three services: mycartridge.http.payment.list
, mycartridge.http.payment.get
, and mycartridge.ftp.getPriceList
; this creates the following logging structure:
Although they are created and managed in the same place, unlike custom logs, these logs don't count toward the quota.
Setting Log Levels
Log levels are adjusted in Administration > Operations > Custom Log Settings.
If a logging category doesn't have a log level specified, it inherits its parent log levels. This allows groups of services to have their logging enabled/disabled at the same time.
For example: for the services described above, you might create the following log categories.
Warn
Enable | Log Category |
---|---|
services | |
✔ | mycartridge.service.ftp |
Info
Enable | Log Category |
---|---|
mycartridge.service.http.payment | |
✔ | mycartridge.service.http.payment.list |
Debug
Enable | Log Category |
---|---|
✔ | mycartridge.service.http.payment.get |
✔ | mycartridge.service.http.payment.list.log |
In this example, everything in the services.ftp
category is set to the warning
log level, so comm
logs are not generated for the mycartridge.ftp.getPriceList
service. The mycartridge.http.payment.get
category generates head
, comm
, and log
logs with debug
level logging. The mycartridge.http.payment.list
category generates head
and comm
logs with info
level logging and a log
log with debug
level logging.
Filtering Logs
You might need to filter sensitive or private data, such as credit card numbers, so that it's not logged. You can do this in two ways:
Example 1: Filter a System-Provided Log Message
This example shows how to add a filterLogMessage
callback to the service definition to filter log messages.
Example 2: let the ServiceCallback
provide the log message
This example shows how to capture log messages using getRequestLogMessage
, convert them to log messages and filter or edit them.
Web service response Examples
This section shows typical responses from a simple web service.
Using HTTPResult as an example (all other result objects for other service types follow the same schema):
for a Simple HTTP GET Request That Was Successful, You Get Back:
for a Simple HTTP GET Request That Failed, You Get Back:
for a Simple HTTP GET Request That Failed Due to 404, You Get Back:
When You Hit the Rate Limit, You Get Back:
When You Hit the Circuit Breaker, You Get Back:
When You Hit the Timeout, You Get Back:
In Business Manager:
- make sure the cartridge containing your script is in the cartridge path.
- make sure that the web service is enabled.
- make sure that the web service is set to Live and not Mocked.
In UX Studio:
- make sure that you point to your initialization script in your package.json.
- make sure that your initialization script has a service definition for your web service.
- make sure that your service definition includes callback objects that handle the web service response.
- make sure that you’ve written a script that calls your web service
- Make sure that your web service is available.
When you upload and run a pipeline with a script node that uses a WebReference2
object to invoke a WSDL file, Salesforce B2C Commerce automatically generates classes from the WSDL using Apache CXF.
The generated classes are automatically added to the webreferences2
package. You use the generated classes in a B2C Commerce script to call the web service operations and process any response from the web service.
B2C Commerce implements SOAP web services through the dw.ws
package port
, webreference2
, and WSUtil
classes.
Overview
The diagram below assumes you’re using the dw.ws
package to implement web services.
For additional information about transport-layer and application-layer security, see [Web Service Security](#web-service-security.
B2C Commerce also maintains a legacy implementation that uses the webreferences
object and Axis 1.4 to generate classes from the WSDL. This legacy implementation is deprecated and will be removed in a future release.
- SOAP 1.1 and SOAP 1.2
- WSDL 1.1
- Apache CXF
- JAX-WS for all features except WS-addressing, attachments, or asynchronous calls.
- https 1.0 and 1.1
RPC/Encoded WSDLs aren’t supported. However, we do support RPC/Literal, Document/Encoded, and Document/Literal WSDLs.
Integrating a web service into your storefront is relatively straightforward.
-
Create the following files:
- filename.wsdl - the WSDL file for the web service.
- filename.jks - (optional) if you’re using a java keystore file for WS-Security, it must have the same filename as the WSDL.
- filename.wsdl.properties - (optional) if you’re using the properties file to generate fully qualified class names to avoid class name collisions.See Resolving Namespace Collisions for WSDLs and Associated Files below.
The filename for all three files must be identical for the files to be used by B2C Commerce. For example, if your WSDL file is named
HelloWorld.wsdl
, then the other files in the directory must be namedHelloWorld.wsdl.properties
, andHelloWorld.jks
.If you have elements in a WSDL schema that contain the underscore character, Webreferences2 can encounter problems during code generation. To resolve this problem, you can use the
underscoreBinding=asCharInWord
property to control code generation. To direct Webreferences2 to use theunderscoreBinding
property, create a properties file in the same directory as the WSDL file. The name of the property file is<wsdl_name>.wsdl.properties
, where<wsdl_name>
is the name of the WSDL file. Also, if you’re migrating from Webreferences to Webreferences2, you can expedite the process by directing Webreferences2 to generate arrays instead of lists. To specify that you want to use arrays instead of lists, setcollectionType=indexed
in the<wsdl_name>.wsdl.properties
properties file. -
Place the files in the
webreferences2
folder in your cartridge. -
Add a service definition to your service registry script for the SOAP web service.
Example; Simple SOAP ServiceDefinition
The ServiceDefinition must specify:
-
initServiceClient callback to get the following using the
dw.ws
package:- a
WebReference2
object - a service port
- WSDL request parameters This callback must also set the serviceClient property for the Service.
The webreference2 object is required to generate the classes for the WSDL, which you must use to call the web service. When you’ve created this callback you can call the pipeline to generate the API for the WSDL. You might want to skip to the steps where you develop the pipeline and run it, so that you have the WSDL API available, and then finish the task of creating the service definition.
- a
-
createRequest callback to set the WebReferences2 method to call and return a requestData object. If you’re using WS-Security, this is where you’ll construct the security hashmap.
-
To implement transport layer security for TLS/SSL, add the certificates that you want to use for your SSL connection, to your instance using Business Manager. See Importing Certificates for an Instance.
-
To implement WS-Security to sign, encrypt or decrypt soap messages:
-
for a JAX-WS web service, using the
dw.ws
package:-
Get a certificate from a known certificate authority or trusted provider to sign the SOAP message to the web service. You must provide a keystore for the WS-Security actions: Signature, Encryption, and Decryption.
-
Place the keystore in the webreferences2 folder in the same cartridge as the WSDL file.
The name of the keystore must be the same as the WSDL file and the file extension must be that of the keystore type (jks or pkcs12). For example, for the
CheckFraud.WSDL
service and a pkcs12 keystore type, the keystore must be namedCheckFraud.pkcs12
. -
In your B2C Commerce script that invokes the web service, create a request and response security configuration. The security configuration is a HashMap, whose first element defines the actions you want B2C Commerce to take: whether to add a timestamp, encrypt the message, sign the message, or other actions. The other elements in the HashMap assign a value to constants defined for the WSUtil class.
Create a separate security configuration for the request messages and the response messages and pass them both into the
setWSSecurityConfig(port : Object, requestConfigMap : Map, responseConfigMap : Map)
class to set the request and response security configuration for the web service.Example:
-
You must create a pipeline, even if you intend to call the script using a hook for an OCAPI application, because you must run the pipeline to generate the classes for the WSDL. To generate the classes, the script must get a
webreferences2
object. When the classes are generated, however, you can call the script using an OCAPI hook. However, if the WSDL changes and you need to generate a new version of the classes, you must run the pipeline again. -
-
-
execute callback to make the service call.
-
parseResponse to parse the result of the call.
-
-
Make sure your cartridge is in the path for your instance and upload the cartridge to the server. This initializes the Service objects, so that they can be accessed when calling web services.
-
Develop a pipeline to call the web service and create a script node that points to your web service script.
-
Execute the pipeline in the storefront, either by navigating to a page that calls the pipeline or by calling the pipeline manually, by adding the pipeline to the end of the URL after the site name. For example:
www.mycompany.com/default/Pipeline-Start
-
Download the classes generated by B2C Commerce in Studio. Click
, select your server connection, select CommerceCloudServer, and then Download Web Service API.
You must execute the pipeline at least once to generate the classes.
You must create a pipeline, even if you intend to call the script using a hook for an OCAPI application, because you must run the pipeline to generate the classes for the WSDL. To generate the classes, the script must get a
webreferences2
object. When the classes are generated, however, you can call the script using an OCAPI hook. However, if the WSDL changes and you must generate a new version of the classes, you must run the pipeline again.The
WebReference2
script class generation process uses the name of the WSDL service and port elements to create a class representing the service or port. If the service or port name contains an underscore character, the generated class name might or might not contain the underscore character based on naming rules used in the code generation process. Regardless of this, callingWebReferences2.getDefaultService()
orWebReferences2.getService(String, String)
resolves the service and port element names to the corresponding script classes. -
Create an ISML template to show the results of the web service and trigger a page refresh when the information shown changes.
-
Troubleshoot any errors using the request log and customerror development logs. See Troubleshooting Web Services below.
See Web Service Security.
Some web service integrations require the use of public key infrastructure (PKI) for application-layer web security, in which any messages exchanged are signed or encrypted to ensure that messages aren’t tampered with. A web service might also require secure communication with certificates issued by a known certificate authority, such as VeriSign, GoDaddy, or Comodo.
X509 certificates are used for application layer security. See Web Service Security.
When calling a web service from a script file, B2C Commerce generates dw.ws.Port
and supporting classes, using the default namespace webreferences2.<wsdl_file_name>.
If your web service WSDL has many different types with the same name, compilation errors can occur because the type classes are all put in the same namespace package. To resolve this issue, you can specify that you want B2C Commerce to generate a namespace-aware Port
and supporting classes, by including a properties file in the same location as your WSDL file. In this properties file, you specify the property as follows:
For B2C Commerce to apply namespace support, the properties file name must be specified as follows:
For example, if your WSDL file is HelloWorld.wsdl
, the properties file must be HelloWorld.wsdl.properties
and it must be placed in the same webreferences2
directory as the WSDL file itself.
In your B2C Commerce script file, create objects using the WebReference2 class. For example, if the namespace for HelloWorld.wsdl
is com.test.wsdl
, creating objects for the namespace requires the qualified name to be:
Q: I’m seeing an error that references security headers and is similar to the following: "com.ibm.wsspi.wssecurity.SoapSecurityException: WSEC....."
A: The request requires a username and password token in the request header. Make sure when constructing this request that the correct credentials (as provided by the web service being connected to) are included.
Q: I’m seeing an error that references 'FaultMessage', however, everything looks syntactically correct. What is wrong and how can I fix it?
A: When the Java files get created, the classes get created with an '_Elemen
t' suffix. What this means is that, for a WSDL element 'fmt_FaultMessage
' there’s a class with the name 'Fmt_FaultMessage_Element.java
' created (when executing wsdl2java). The WSDL and code to reference this must be adjusted accordingly. To do this, modify the WSDL to change all references to (in this example) 'fmt_FaultMessage
':
Q: I’m seeing an error that the WSDL file can't be located in B2C Commerce, but I know the WSDL file is there. The error is: "Script exception in line 42
A: Make sure that the WSDL file is in the cartridge’s webreferences2
directory and make sure the pipeline executing/calling it's in the same cartridge (as the WSDL file).
Q: I’m having difficulty invoking a method that expects an ArrayOf type as a parameter, how can I get this to work?
A: To pass an ArrayOf structure as a parameter to a method in a script, one should follow the following conventions (keeping in mind that the exact implementation will vary depending on your specific code/logic): request.setSomething([theArray]);
or request.setSomething(new Array(x))
;
Q: I’m trying to integrate with a web service that has fields defined as dateTime and keep getting this error: "Cannot convert [Calendar id=19206138] to java.util.Calendar "
A: All variables have setter methods. Salesforce recommends always using setter methods. However, when using primitive types it isn't necessary, but by using setters you’ll always be safe.
Q: I’m running into some data-type specific issues. Which data-types aren’t supported?
A: The following data types aren’t supported:
- NonNegativeInteger
- NonPositiveInteger
- UnsignedByte
- UnsignedInt
- UnsignedLong
- UnsignedShort
The following is an example element in a WSDL document with a name of 'return':
In order to access an element with the name "return" you must add an underscore to the name.
With an underscore in the name, you can access all the properties in the object.
Errors shown for names without an Underscore
Attempting to access the element causes some of the following errors:
Example 1:
Using the following pseudocode:
Throws the following error:
Example 2:
Using the following pseudocode:
Throws the following error:
Carefully consider a timeout strategy for web services.
SOAP web service connections use a default timeout of 2 minutes for storefront and B2C Commerce tool requests and 15 minutes for jobs. If the timeout of the calling script is less than the default, the script timeout is used.
To ensure the site's responsiveness, configure a low timeout.
The HTTPClient method times out at 2 minutes for storefront and B2C Commerce tool requests and 15 minutes for jobs.
Salesforce recommends setting timeout values through the service configuration.
The timeout you configure for a service is a connection and read timeout. If each connection/read duration is just below the timeout duration, the total time of the service might be much larger than the timeout value. For example, with a 5-second timeout, with a 4-second connection attempt, followed by reading two chunks of data at 4 seconds apiece, takes about 13 seconds total, but doesn’t time out.
If you don't configure the service timeout values, it’s also possible to set port timeouts using API methods, but these aren’t monitored or included in the service status analytics. However, information about these timeouts is included below.
Port Timeouts for SOAP Web Services
Use the dw.ws.WSUtil
class to set read/connection timeouts for ports using the setConnectionTimeout(timeout, port)
and setRequestTimeout(timeout, port)
methods. The minimum connection timeout is 100 miliseconds and the maximum connection timeout is 15 seconds.
There are two layers of security that you can configure for communication between your storefront and an external web service. At the transport layer, you can use certificates to identify both parties of a transaction. At the application layer, you can encrypt or sign content with another certificate (X.509), to ensure that the contents of your messages aren’t tampered with.
The diagram below shows the communication between a Salesforce B2C Commerce pipeline and an external web service. This diagram assumes you’ve created a custom pipeline and script that invokes the web service, creates SOAP messages, and signs or encrypts messages to the web service.
When the web service is invoked via https, B2C Commerce automatically uses the client private key that you’ve stored in your instance via Business Manager, using the host name you’ve provided for that key. You can import SSL certificates used for two-factor authentication into your instance. TLS certificates are used for communication with web services or when using dw.net.HTTPClient
.
When the transport layer negotiation and handshake is complete, your B2C Commerce script sends a SOAP message to the web service.
If you use the B2C Commerce implementation of web services in the dw.ws
package, then If the web service requires encryption or signing of SOAP messages, B2C Commerce uses the X509 certificate stored in the instance keystore with the WSDL in the webreference2
folder in your cartridge. In this case, the private key is usually stored in Business Manager in a site preference or custom attribute and referenced in the script, so that the private key doesn't have to be included directly in the script.
You can also choose to use dw.net.httpClient
and the crypto package to send and sign a SOAP message if you can't use the B2C Commerce implementation of web services. This isn't recommended and only necessary if you require that the web service X509 certificate be stored in the Business Manager instance.
For both transport layer and application layer security, you import private keys with certificates and trusted certificates into the Business Manager instance keystore. However, if you want to use WS-Security to automatically encrypt and decrypt SOAP messages, these certificates must be stored in a cartridge.
When you import certificates into Business Manager, you also configure additional information required when using the keys and certificates, such as an alias or a service provider host name. The alias indicates to B2C Commerce which URL requires the certificate.
Private keys and certificates are stored per instance and can be used across all sites and organizations for that instance. You can store up to 50 entries (keys or certificates) in an instance key store. Each entry in the key store must have an alias. Once given, the alias can't be changed. To change an alias, you must remove the certificate from the keystore and reimport it.
Each private key can be associated with up to five host names. You can import the following private key file types: .pfx or .p12. You can import the following types of trusted certificates: .pem,.cer,.crt,.der. You can also import X509 certificates.
Once imported, the certificates are used whenever communicating with a web service via https.
In releases before B2C Commerce 14.4, X509 certificates were stored with the .wsdl file in a keystore in the webreferences2
folder. It's still possible to do this, but it isn't recommended if you’re only signing messages and not encrypting them, as storing certificates in the instance keystore is more secure and makes managing certificate expiration easier.
Script methods used for X509 certificates stored in the instance Keystore
To perform signing and verification using certificates stored in the instance keystore, you must use methods that include KeyRef parameter in the method signature.
These methods include:
dw.crypto.Signature.sign(String message, KeyRef privateKey, String digestAlgorithm)
dw.crypto.Signature.signBytes(Bytes contentToSign, KeyRef privateKey, String digestAlgorithm)
dw.crypto.Signature.verifySignature(String signature, String contentToVerify, CertificateRef certificate, String digestAlgorithm)
dw.crypto.Signature.verifyBytesSignature(Bytes signature, Bytes contentToVerify, CertificateRef certificate, String digestAlgorithm)
dw.crypto.KeyRef(String aliasS)
dw.crypto.KeyRef(String alias, String password)
You can use the helper classes KeyRef
and CertificateRef
as references to keys in the keystore. They have a constructor that takes a string that is an alias of a private key KeyRef
or a trusted certificate CertificateRef
in the keystore.
Q: What features of WS-Security does Commerce Cloud Support?
A: B2C Commerce supports all features of the WS-Security standard except addressing.
Q: What is a key store?
A: A keystore is a storage facility for cryptographic keys and certificates.
Q: What's the difference between a certificate and a trusted certificate?
A: A certificate is private; a trusted certificate is a public certificate issued from a trusted certificate authority.
Q: Why can't I see the Certificates & Private Keys module?
A: You must have the required permissions to see the module. Request permission for the Private Keys and Certificates Business Manager module from your administrator.
Q: How many TLS certificates can be imported per instance?
A: Up to 50 key entries can be stored per B2C Commerce instance and organization. Key entries include both private keys and certificates.
Q: How many host names can a private key be associated with in Business Manager?
A: Each private key can be associated with up to five host names.
Q: If there’s an error when using a certificate, where is it logged?
A: See the error log files under Administration > Site Development > Development Setup > Log Files.
Q: How do I scrub logs for sensitive information?
A: When URLs written to the service framework's communication logs must be scrubbed for sensitive information, use dw.svc.ServiceCallback.filterLogMessage
to filter the request URL as well as the request and response bodies.
Q: Can I use the signatureKeyIdentifier and encryptionKeyIdentifier?
A: The WebReferences2 integration with WS-Security enables you to set values for signatureKeyIdentifier
and encryptionKeyIdentifier
using constants in the WSUtil
class. For signatureKeyIdentifier
, use the WS_SIG_KEY_ID
and for encryptionKeyIdentifer
, use WS_ENC_KEY_ID
. s
See the B2C Commerce Script API documentation for the default values that WebReferences2
uses and its permissible options.
Q: Is sensitive data included in web service logging?
A: By default, logging data is filtered to prevent logging sensitive data. It's possible to enable logging this information if it's required. For more information, see the description of the comm logging level in .
You can import Private Keys and SSL certificates used for two-factor authentication into your instance. TLS certificates are used for communication with web services, file transfer over WebDAVClient, or when using dw.net.HTTPClient
or any of the dw.crypto
classes that use a KeyRef
parameter. Salesforce B2C Commerce uses an internal password to encrypt the instance keystore.
If you have an integration to an external server using SSL/TLS, the SSL certificate that is installed at the external server must be issued by a Certification Authority (CA) that the Commerce Cloud B2C Commerce server recognizes. By default, B2C Commerce only recognizes the root CAs that ship with Oracle's Java platform. However, you can add additional CA certificates to the customer keystore. Certificates added to the customer keystore are checked when establishing outbound SSL connections.
-
Select Administration > Operations > Private Keys.
-
On the Private Keys and Certificates page, you can search for a certificate or navigate the grid to select one.
Select 10, 25, 50, or 100 items to appear on a page.
-
If you’re importing a new version of an existing certificate and want to use the same alias, you must first delete the existing certificate. Aliases for all entries in the keystore must be unique.
-
To add a new certificate or private key:
-
Click Import or Upload a new private key or certificate.
-
In the Import Private Key or Certificate window, enter a certificate or private key file name, or click Select... to open the File Upload window and select the file to import.
Only the following file types are allowed:
- Trusted certificates: .crt .pem .cer .der
- Private Keys: .p12 .pfx The certificate appears in the certificate list..
-
-
To add host names to a private key:
-
Click the dropdown to the right of a private key and select Manage Hosts.
-
On the Manage Hostnames window, enter the host name, for example,
www.sitegenesis.com
, and click Add. -
Click Save.
-
-
If you’re importing:
- A trusted certificate (*.crt): enter the following:
- Alias: Enter an alias used to refer to this certificate when using any of the B2C Commerce script dw.crypto package methods that specify an alias. The alias shouldn't contain spaces or special characters in B2C Commerce script. B2C Commerce tells you if the alias isn't unique for your instance.
- A private key (*.p12): enter the following: - Source Password: Enter a password for the encryption of the key file entered in the instance keystore. - Alias: enter an alias used to refer to this certificate when using any of the B2C Commerce script dw.crypto package methods that specify an alias. The alias shouldn't contain spaces or special characters in B2C Commerce script. B2C Commerce tells you if the alias isn't unique for your instance. You might want to include the web service name or service provider name. - Host Names: If you’re using the key or certificate for transport layer security, enter the DNS name of the server as reached by the client. For example:
www.paypal.com
. B2C Commerce uses the host name to determine what certificate to use. You can add two or more host names, separated by a comma. If you importing a certificate specified by one of thedw.crypto
package methods that takes a KeyRef argument, you don't need to enter a hostname. If you’ve more than one private key in your keystore, the host name must be set to the target host you call viadw.net.HTTPClient
ordw.ws.WSUtil
. Otherwise, B2C Commerce can't guarantee that the correct client certificate is used for the call.
- A trusted certificate (*.crt): enter the following:
If you’re importing a new version of an existing certificate and want to use the same alias, you must first delete the existing certificate. Aliases for all entries in the keystore must be unique.
-
Select Administration > Operations > Private Keys and Certificates.
-
On the Private Keys and Certificates page, you can search for a certificate or navigate the grid to select one.
-
To delete a certificate (alias or host name):
- Click the Alias checkbox (to select all certificates) or select one or more certificates, and then click Delete.
- Click the
icon to the right of a certificate and select Delete.
Credit card encryption is performed internally on Salesforce B2C Commerce for secure storage of sensitive information. Credit card encryption, key generation, and re-encryption is automatic. B2C Commerce provides the ability to monitor this process for customers undergoing a PCI audit, to demonstrate the current state of the system.
-
Select Administration > Operations > Payment Instrument Encryption Keys.
The Payment Instrument Encryption Keys Page appears.
-
Use the page to determine the status of your encryption keys and the dates when keys are generated.
Some web service integrations require the use of public key infrastructure for application layer web security, in which any messages exchanged are signed or encrypted to ensure that messages aren’t tampered with. A web service might also require secure communication with certificates issued by a known certificate authority, such as VeriSign, GoDaddy, or Comodo.
X509 certificates are used for application layer security.
-
Get a certificate from a known certificate authority or trusted provider to sign the SOAP message to the web service. You must provide a keystore for the WS-Security actions: Signature, Encryption, and Decryption.
-
Place the keystore in the webreferences2 folder in the same cartridge as the WSDL file.
The name of the keystore must be the same as the WSDL file and the file extension must be that of the keystore type (jks or pkcs12). For example, for the
CheckFraud.WSDL
service and a pkcs12 keystore type, the keystore must be namedCheckFraud.pkcs12
. -
If you have additional certificates that you want to use for your SSL connection, add them to your instance using Business Manager.
-
Create a DWScript that does the following:
- Defines a HashMap and put your client key and password, service key and password, username and password into it.
- Defines a HashMap for the web service request that configures the actions of the interceptor actions when a call is made to the web service. Interceptor actions are defined through methods in the WSUtil class.
- Defines a HashMap for the web service response that configures the interceptor actions for the return message.
- Uses the
WSUtil.setWSSecurityConfig
method to configure the actions on the server - Calls the web service
-
Create a custom pipeline with a script node and assign it to the script you’ve created.
This template shows how to use the WSUtil class to configure WS-Security for a Web service call in Salesforce B2C Commerce. However, it doesn't use sample data and can't be used to run an actual web service.
JSON (JavaScript Object Notation) is a human-readable, easily parsed or generated data-interchange language. Salesforce B2C Commerce provides a top level JSON class to make it simple to exchange objects between your server and client. The B2C Commerce implementation is based on the json2.js implementation of JSON.
JSON objects are useful if you need to create a complex data object of an arbitrary depth. For example, if you have a main product with options that depend on other attributes, such as gender or size.
B2C Commerce provides a parsing method that can be used to construct a JSON object from a JSON string used as the value of an attribute field. Salesforce recommends using the parse(json : String, reviver : Function) : Object
function for this purpose.
The object can then be further manipulated using any ECMA-compliant language, such as JavaScript . The object can then be stringified using the B2C Commerce-provided stringify() method and transferred to the client.
Alternatively, a JSON string used as the value of an attribute field can be transferred to the client and then parsed to create an object for further operations.
JSON objects are not recommended for general use, because JSON does not handle recursive structures effectively.
Salesforce B2C Commerce JavaScript supports the E4X extension to JavaScript. This extension supports the direct manipulation of XML data in scripts, without the need to work DOM or other intermediate structures. It's standardized as ECMA-357.
- To create an XML object
-
Specify the following:
-
You can read values from an XML object the same way you would from standard ECMAScript objects:
-
You can also directly modify an XML object:
As a working example, the next section shows how to call an amazon.com service. Amazon supports Web Service-based calls and REST calls. REST services can be called as a straight URL and return XML. The XML language support is used here to parse the returned result from the amazon.com service.
See the Amazon Simple Services Developer's Guide (www.docs.amazonwebservices.com\) for more information on developing Web Services for Amazon.
- To call the amazon.com REST service, specify
If you don't see a result, validate that amazon.com still returns data with the same XML format, particularly with the same namespace identifier.