5Best Practices for Designing Client Application
Best Practices for Designing Client Application
This chapter provides best practice recommendations that allow you to design client applications that interface optimally with Oracle CRM On Demand using Web Services On Demand. It contains the following topics:
Best Practices for Integration Design
This topic describes best practices for optimizing the design of client applications.
Sending of Web Services Requests to Oracle CRM On Demand
Oracle CRM On Demand processes Web services requests in a synchronous manner, therefore client applications using a single session must send requests in a synchronous manner. If the client application needs to send messages asynchronously, multiple sessions must be used.
Flushing of Caches
In Oracle CRM On Demand, there are internal caches that store metadata information such as field customization data, access or privilege settings, book information and so on.
For stateless Web services only, users can flush the caches to reload any metadata information that has changed recently. You use the MetadataChangeSummaryQueryPage method to determine whether there have been any metadata changes; see MetadataChangeSummaryQueryPage.
In the case of session-based Web services (stateful Web Services), the same flushing of caches would only occur on logging in again.
Best Practices for Flushing of Caches
The best practices for flushing of the caches are as follows:
You are advised not to flush caches unless really necessary, because it affects throughput.
If you detect stale metadata, you use a flush cache flag to reload the caches.
You can use the MetadataChangeSummaryQueryPage method to check whether the metadata has changed.
Usage
To flush the caches, you include the SOAP header element <FlushCache> in requests. The element can contain the values true
or 1
to indicate that caches are to be flushed. Any other value is considered as false.
The following shows a SOAP message containing the <FlushCache> element:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http:/
/www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-
1.0.xsd">
<soap:Header>
<wsse:Security>
<wsse:UsernameToken>
<wsse:Username>user@ondemand.com</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-
wss-username-token-profile-1.0#PasswordText">password</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
<FlushCache xmlns= "urn:crmondemand/ws ">true</FlushCache>
</soap:Header>
<soap:Body>
... Input request or payload here ......
</soap:Body>
</soap:Envelope>
Using Stateless Web Services
Stateless Web services use server resources more efficiently and can reduce the cost of implementation as customers do not need to implement session pooling algorithms in their client applications. The best practices for using stateless Web services are described in the following sections.
Using Both Stateful and Stateless Web Services
Customers might decide to implement both stateful and stateless Web services originating either within the same client application, or they might decide to implement one application that is stateless and another that is stateful. While Oracle CRM On Demand supports the use of both login mechanisms, it is recommended that stateful and stateless Web services calls are not mixed.
For example, if you follow this sequence:
Perform a stateful web service login and store the JSESSIONID value
Issue a stateless Web service request while providing the JSESSIONID from the stateful request.
This sequence results in the stateless Web service call using the session associated with the JSESSIONID and will therefore not be a stateless request. The JSESSIONID will not be invalidated after processing the request, and the user must perform a log off for the session because it was created through an implicit login.
When issuing a stateless request, a client can keep the resulting Java session alive using the <SessionKeepAlive> parameter. This results in a session ID being returned to the client application. To maintain server affinity, the session ID returned by the initial request must be returned in subsequent requests. For many development platforms this is the default behavior, that is, the cookie is returned with the next request.
If the <SessionKeepAlive> parameter is not set to true, the session ID does not identify a specific session as it does for stateful requests, however it does identify the specific server on which the session resides. Including this session ID for subsequent requests ensures that the request is routed to the correct server (not doing so might result in the subsequent request being routed to another server and the establishment of a new session on that server).
When the <SessionKeepAlive> parameter is set to true, the session ID value functions similarly to stateful Web services and allows a subsequent request to be handled by the session associated to the session ID value. Note that there is no logoff command for stateless Web service even if the <SessionKeepAlive> parameter is set to true; Oracle CRM On Demand, server-side session management logs off sessions as required to ensure equitable allocation of resources.
Avoid Multiple Concurrent Requests
Avoid issuing multiple concurrent requests for the same application unless absolutely required. If you do send multiple concurrent requests, and if you receive a RIP_WAIT error, or server unavailable error, the server might be busy due to the number of concurrent requests it is handling. If this happens, do one of the following:
If possible, try the request again later, as the load on the server might decrease.
Most load conditions are rare and temporary. You might never see one during development.
Retry with an exponential backoff. The client can be implemented such that retries are issued automatically using an exponential retry rate (that is, retries occur after 100ms, 200ms, 400ms, 1600ms and so on).
Use Sort Criteria when Using QueryPage
If the QueryPage method is used as a stateless transaction, each request for an additional page of data returns any records that have been added or updated since the initial query. Any records that have been deleted since the first request will no longer appear in the result set.
It is recommended to use sort criteria to reduce the possibility of returning the same record when paging through results using the QueryPage method:
Use sort criteria on the Id field, which helps in most simple cases.
Use sort criteria on a field that is being filtered to help improve performance.
Use a stateful QueryPage Web service request, if it is required to paginate through a snapshot of data.
Setting and Querying Blank Values
When updating or querying for blank values the best practice is to specify isNull instead of leaving the value blank.
As an example, the AccountName and Location fields form a user key for updating or querying Account records. Location is not a required field, therefore a null or blank value can be set for this field. The best practice is therefore to specify isNull for Location instead of blank.
Working with Opportunity Product Revenue Records
When implementing a client application that inserts or both inserts and updates Product Revenue records associated with an Opportunity, it is important to ensure that the Revenue record is associated not only with the Opportunity but also with a Product record. This is because Opportunity Revenue records that do not have an associated Product will not appear within the Oracle CRM On Demand UI. These records will appear in Forecast and Opportunity revenue roll-up but are not editable using the UI or Web services.
Error Handling and Logging
Error handling and logging are essential when developing a client application. The client application must provide for:
Logging of detailed information about the error observed.
Logging of the body and header information of all SOAP requests and responses. For the resolution of some errors, the actual SOAP request can be extremely useful in identifying the root cause of a problem. For more information, see the following topic.
A call stack, which can be extremely important when analyzing problems and can provide useful hints that might reveal contributing factors to the problem.
Entry points wrapped in log messages. The ability to identify entry and exit of Web service calls is important when analyzing issues.
If a Web service request returns an error, the ability to analyze the result, stop immediately, or continue depending on the severity of the issue reported.
End points that are not hard-coded.
Dynamic server name and protocol configuration
To handle the errors, a client application needs to be able to understand the SOAP fault that is returned in the SOAP response when an error is encountered in processing a Web service request.
For information about SOAP faults and error codes returned by Oracle CRM On Demand, see Oracle Web Services On Demand Guide Troubleshooting Guide.
Logging of SOAP Requests and Responses
SOAP requests and SOAP responses are important information that can assist you in troubleshooting your integration when issues arise, as they capture exactly what was sent to and received from Oracle CRM On Demand. Logging the requests and responses can also help you better understand your integration.
It is a best practice and strongly recommended that your integration logs any SOAP request sent to Oracle CRM On Demand Web Services and any SOAP response received for easier troubleshooting of your integration. It is also beneficial to log the SOAP requests and responses when an issue arises that requires a service request to be created by technical support. The logs with the SOAP requests and responses can help the Oracle CRM On Demand team with reproducing and identifying the issue.
There are different ways in which you can log SOAP requests and responses, for example:
Depending on the technology that you use to implement your client application, your client application can output the SOAP requests and responses to log files when they are sent and received in the application. For example, with Java API for XML Web Services (JAX-WS) this can be done by implementing SOAP message handlers. With ASP.NET it can be implemented by using the SOAP extensions framework.
You can use proxies to record any HTTP traffic between the client and Oracle CRM On Demand.
Handling Outages and Failures
The client application must contain a mechanism to recognize when the Oracle CRM On Demand application is not available, and be able to persist in a dormant state. This mechanism can either be achieved manually or programmatically; for example:
A process can become dormant if it receives a HTTP 404 error message and retry after several minutes.
A process can alert an administrator and shut down after x failed attempts.
A situation might arise where it is unknown if an operation has succeeded or not. In this situation, if the client application can detect duplicate errors, you can retry an insert operation with Oracle CRM On Demand user keys allowing you to uniquely identify records. You can identify lost updates by examining modification dates on records.
Understanding Web Services Transactions
When designing client applications, remember that Web service requests can be treated as transactions. A transaction succeeds if all operations in the transaction are successful, otherwise the transaction is rolled back.
For Web Services On Demand calls, the transaction boundary is at message level. That is, if a Web service request is received with 10 operations (for example, 10 inserts), and if the 10th operation fails for some reason, then all of the 9 previous successful operations are rolled back and the initial state is restored.
A transaction is created only when there are operations on more than one record. Transactions are supported for both Web Service v1.0 and Web Services v2.0 calls.
Best Practices for Generating Web Services Proxy Classes in Java Environments
This topic provides information on commonly encountered issues while generating Web services proxy classes in the Java integrated development environments (IDE) Oracle JDeveloper and Axis. Solutions and workarounds are provided to successfully generate the Web Services v2.0 API proxy classes in these Java IDEs.
Oracle JDeveloper Workaround
For WSDLS that have a large number of fields, proxy generation succeeds for all WSDL files, but compilation might fail due to the doSerialize() or do Deserialize() method being more than 64KB in size.
To work around the failure
Avoid proxy class compilation failure.
See Avoiding Proxy Class Compilation Failure Due to the Java 64KB Limit.
Increase the Java heap size in the jdev.conf file.
Axis Workaround
Proxy generation can fail for large WSDL files, and throw the following exception:
java.lang.OutOfMemoryError: Java heap space
To work around the failure
Remove unused child objects from WSDL files.
Increase the Java heap size in the wsdl2java.bat/wsdl2java.sh file.
To remove child objects from Web Services v2.0 WSDL files
In the <Types> section in the WSDL, find the <xsd:schema> element with the target namespace "urn:/crmondemand/xml/ParentName/Query", and do the following:
Traverse to the <xsd:complexType> element with the name "ParentNameQuery".
Remove the <xsd:element> element with the name "ListOfChildNameQuery".
Remove the <xsd:complexType> element with the name "ListOfChildNameQuery".
Remove the <xsd:complexType> element with the name "ChildNameQuery".
Find the <xsd:schema> element with the target namespace "urn:/crmondemand/xml/ParentName/Data" and do the following:
Traverse to the <xsd:complexType> element with the name "ParentNameData".
Remove the <xsd:element> element with the name "ListOfChildNameData".
Remove the <xsd:complexType> element with the name "ListOfChildNameData".
Remove the <xsd:complexType> element with the name "ChildNameData".
Avoiding Proxy Class Compilation Failure Due to the Java 64KB Limit
The Java language enforces a size limit on member functions, which cannot exceed the size of 64KB (see http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html#9279.
As part of the process of generating proxy classes from the Oracle CRM On Demand WSDL files, the serializer and deserializer methods that are generated can exceed 64KB in size. Therefore, a process like the following can result in a compilation error:
Generate proxy classes using Oracle JDeveloper 11g or any other Java integrated development environment (IDE).
Compile the proxy classes.
An out of memory error message is thrown due to the 64KB limit on member functions. For example, the error message for Oracle JDeveloper 11g is:
code segment of method doDeserialize(oracle.j2ee.ws.common.streaming.XMLReader, oracle.j2ee.ws.common.encoding.SOAPDeserializationContext) too large
This occurs for any Java compiler depending on the number of fields that are generated in the doSerialize or doDeserialize methods, as the 64KB limit is a Java VM limitation.
There are two possible workarounds:
Split the doSerialize method.
You can split the doDeserialize () and doSerialize () methods into multiple smaller methods to bypass the 64KB limit. The sample code snippets in following figure and second figure in this topic illustrate the splitting of the doSerialize method.
Delete unused fields generated in the serialize methods.
You can trim the doSerialize method by deleting unused fields, which is specific to each client integration.
public void doSerialize(java.lang.Object obj, XMLWriter writer, SOAPSerializationContext context) throws Exception { // @GeneratedBlockBegin (value={"oracle.j2ee.ws"} ); activity.proxy.types.crmondemand.xml.activity.data.ActivityData instance = (activity.proxy.types.crmondemand.xml.activity.data.ActivityData)obj; if (instance.getModifiedDate() != null) { myns3_dateTime__java_util_Calendar_DateTimeCalendar_Serializer.setNullable( false ); myns3_dateTime__java_util_Calendar_DateTimeCalendar_Serializer.serialize(instance.getModifiedDate(), ns2_ModifiedDate_QNAME, null, writer, context); } if (instance.getCreatedDate() != null) { myns3_dateTime__java_util_Calendar_DateTimeCalendar_Serializer.setNullable( false ); myns3_dateTime__java_util_Calendar_DateTimeCalendar_Serializer.serialize(instance.getCreatedDate(), ns2_CreatedDate_QNAME, null, writer, context); } if (instance.getModifiedById() != null) { myns3_string__java_lang_String_String_Serializer.setNullable( false ); myns3_string__java_lang_String_String_Serializer.serialize(instance.getModifiedById(), ns2_ModifiedById_QNAME, null, writer, context); } if (instance.getCreatedById() != null) { myns3_string__java_lang_String_String_Serializer.setNullable( false ); myns3_string__java_lang_String_String_Serializer.serialize(instance.getCreatedById(), ns2_CreatedById_QNAME, null, writer, context); } if (instance.getModId() != null) { myns3__int__java_lang_Integer_Int_Serializer.setNullable( false ); myns3__int__java_lang_Integer_Int_Serializer.serialize(instance.getModId(), ns2_ModId_QNAME, null, writer, context); } ... }
public void doSerialize(java.lang.Object obj, XMLWriter writer, SOAPSerializationContext context) throws Exception { // @GeneratedBlockBegin (value={"oracle.j2ee.ws"} ); activity.proxy.types.crmondemand.xml.activity.data.ActivityData instance = (activity.proxy.types.crmondemand.xml.activity.data.ActivityData)obj; instance = doSerialize1(instance, writer, context); instance = doSerialize2(instance, writer, context); ... } public activity.proxy.types.crmondemand.xml.activity.data.ActivityData doSerialize1(activity.proxy.types.crmondemand.xml.activity.data.ActivityData instance, XMLWriter writer, SOAPSerializationContext context) throws Exception { if (instance.getModifiedDate() != null) { myns3_dateTime__java_util_Calendar_DateTimeCalendar_Serializer.setNullable( false ); myns3_dateTime__java_util_Calendar_DateTimeCalendar_Serializer.serialize(instance.getModifiedDate(), ns2_ModifiedDate_QNAME, null, writer, context); } if (instance.getCreatedDate() != null) { myns3_dateTime__java_util_Calendar_DateTimeCalendar_Serializer.setNullable( false ); myns3_dateTime__java_util_Calendar_DateTimeCalendar_Serializer.serialize(instance.getCreatedDate(), ns2_CreatedDate_QNAME, null, writer, context); } ... return instance; } public activity.proxy.types.crmondemand.xml.activity.data.ActivityData doSerialize2(activity.proxy.types.crmondemand.xml.activity.data.ActivityData instance, XMLWriter writer, SOAPSerializationContext context) throws Exception { if (instance.getModifiedById() != null) { myns3_string__java_lang_String_String_Serializer.setNullable( false ); myns3_string__java_lang_String_String_Serializer.serialize(instance.getModifiedById(), ns2_ModifiedById_QNAME, null, writer, context); } if (instance.getCreatedById() != null) { myns3_string__java_lang_String_String_Serializer.setNullable( false ); myns3_string__java_lang_String_String_Serializer.serialize(instance.getCreatedById(), ns2_CreatedById_QNAME, null, writer, context); } if (instance.getModId() != null) { myns3__int__java_lang_Integer_Int_Serializer.setNullable( false ); myns3__int__java_lang_Integer_Int_Serializer.serialize(instance.getModId(), ns2_ModId_QNAME, null, writer, context); } ... return instance; }
Entering Telephone Number Values through Web Services
Telephone number values entered through Web service requests and the Oracle CRM On Demand UI are displayed differently both in the UI and in the response to the QueryPage operation. The following table shows how telephone number values are displayed in the UI or within the response to a QueryPage request.
Table Formatting of Telephone Number Values Entered Through Web Services or the UI
Input Mechanism | Formatting in UI | Formatting in Web Service Response |
---|---|---|
Input through Web service |
||
14045550199123 |
1 (140) 555-0199#1123 |
+1 404 5550199 #123 |
140455501991 |
1 (140) 555-0199#1 |
+1 404 5550199 #1 |
+14045550199,123 |
1 (4045550199) 123 |
+1 4045550199 123 |
Input through UI |
||
14045550199123 |
14045550199123 |
+1 4045550199123 |
14045550199 |
1 (404) 555-0199 |
+1 404 5550199 |
+14045550199,123 |
1 (404) 555-0199#123 |
+1 404 5550199 #123 |
Telephone number values differ from other values in that the format of the value impacts the accuracy of the value. When querying for a telephone number value, it is necessary to return the value with formatting.
Recommended Formats for Telephone Numbers
When determining the value to be input through Web Services you must take into account how the telephone number will appear in the UI and in the Web service response.
The following formats are recommended for telephone numbers entered through the UI or Web services, as they are formatted the same way in the UI and in Web service responses:
1 (404) 555-0199 123
1 (404) 555-0199 #123
1 (140) 555-0199#1
1 (140) 555-0199
The following is an example of a request that uses one of the above formats to insert a Contact with telephone number fields.
<ListOfContact> <Contact> <ContactFirstName>Contact</ContactFirstName> <ContactLastName>Name</ContactLastName> <WorkPhone>1 (404) 555-0199 #123</WorkPhone> <PHONE_000>1 (404) 555-0199 #123</PHONE_000> </Contact> </ListOfContact>
The following is the query response:
<ListOfContact xmlns="urn:/crmondemand/xml/Contact/Data" lastpage="true"> <Contact> <ContactFirstName>qq2</ContactFirstName> <ContactLastName>ww2</ContactLastName> <WorkPhone>1 (404) 555-0199 #123</WorkPhone> <PHONE_000>1 (404) 555-0199 #123</PHONE_000> </Contact> </ListOfContact>
Other Considerations for Telephone Numbers
If you use the + character and parentheses () characters together in a Web services request, the number is displayed differently in the UI and Web service response. For example, the input:
+1 (404) 555-0199 #123
is displayed as the following in the Web service response:
+1 404 5550199 #123
and as the following in the UI:
1 (404) 555-0199 #123
It is not possible to modify the telephone number in the UI to display a + prefix for a telephone number, or to remove the parentheses () from a telephone number using Web services. For example, the input:
+1 404 555-0199 #123
is displayed as the following in the Web service response:
1 404 5550199 #123
and as the following in the UI:
1 (404) 555-0199 #123
There are locale considerations when entering telephone numbers. As an example, if the user locale is set to Australia (country code +61) and a Web service request contains the 10 digit telephone number: 0477777777
, then the number displayed in the UI is:
+1 047 777-7777
as the number displayed defaults to the North American Numbering Plan if the country code is not included. In this case, the user locale (Australia) is not considered.
If you enter the same telephone number (0477777777
) in the UI or through import, the telephone number displayed in the UI is:
(04) 7777 7777
where the country code is set to Australia.
To make the behavior consistent across Web service requests and the UI, it is recommended that in Web service requests you prefix the number with the + character and country code. For the previous example, the telephone number in the Web service request would be:
+61477777777
Telephone numbers submitted through Web service requests must not begin with an alphabetic character and must either begin with a numeric value or a + character. For example, updating a telephone number field with the value DO NOT CALL
would result in an error being returned to the client. However, specifying the value 1DONOTCALL
would succeed.
Best Practices for Adhering to Web Service Allotments
This topic lists several best practices to help ensure that you do not exceed the various Web services allotment values.
For the Web Services Operations allotment:
Avoid unnecessary Web services requests:
Avoid issuing the same query multiple times, if you do not expect the set of records returned to change; cache the data locally to avoid repeated requests for the same information.
Issue subsequent page requests when necessary, do not retrieve the entire record set if it is not necessary.
Ensure high data quality to minimize errors (this is especially important for batch requests):
Ensure field values are of the correct type
Include values for required fields in all requests
Do not use invalid Id values when associating records using Web services.
Use the Oracle Data Loader On Demand tool or the Import Assistant for loading large amounts of data into Oracle CRM On Demand.
Use the Export Assistant for extracting large amounts of data from Oracle CRM On Demand.
Include the miniumum set of related objects in QueryPage requests.
For the Web Services Concurrent Request allotment:
Schedule automated or low priority clients to execute during off-peak hours.
When performing more than one operation based on a user's input, send requests sequentially, not in parallel.
Use the Execute method in the Web Services v2.0 API to bundle multiple requests on a set of records of the same type in a single Web service request.
Working with Record Ownership Modes
For most of the record types that support custom books, the company administrator can set up record ownership for the record type in one of three record ownership modes: user mode, book mode, or mixed mode. If you plan to change ownership modes for record types, you must review and test your Web services integrations to ensure that they continue to work. For more information about record ownership modes, see Oracle CRM On Demand Online Help.
Considerations when Rejecting Leads
In the Oracle CRM On Demand UI you can reject a lead by selecting the Reject button on a lead detail page. The status of the lead then changes to Rejected and you must select a value in the Reject Code field and you can enter a value in the Reject Reason field.
For Web Services v1.0 and Web Services v2.0 you can make calls to update the RejectCode and RejectReason fields for the Lead object; however, there is no validation of the Status field for such calls. Therefore, when designing your client applications you must add your own validations to ensure that the Status, RejectReason, and ReasonCode fields are set correctly.
For more information about working with leads, including rejecting leads and lead qualification, see Oracle CRM On Demand Online Help.
Best Practices for Integration Performance
This topic describes best practices for optimizing the performance of client applications.
Batch Processing
With Web Services On Demand, you can perform batch operations that optimize performance by combining multiple requests into one.
Oracle CRM On Demand batch processing has a limit of 20 top-level records for each request and is supported for the following operations:
Insert
Delete
Update
InsertOrUpdate (Web Services v1.0 only)
Because batch calls take longer to process than single operations they must only be used in instances where longer response time would not impact the user experience. However, for such interactive applications, if Oracle CRM On Demand needs to process multiple records of the same type, batch operations increase the performance.
If a single record in a batch causes an error, the entire batch is not processed. For example, a batch of 20 Account inserts where one record contains an error will require all records to be reinserted.
A batch error could result from a data error or other error (for example, network outage, session expiry, and so on). If the error is not data-related, it is recommended that the user logs in again and tries the Web service call again. If the error is data-related, the batch can be split into smaller batches so that the records that do not cause errors can be processed.
Session Management and Pooling
It is recommended that you use stateless Web services as opposed to stateful Web services whenever possible, as described in Using Stateless Web Services. This topic however discusses the best practices for the situations when you use stateful Web services.
For stateful Web services requests, Web Services On Demand uses a session-based security mechanism for which each operation is synchronous.
It is recommended that a user:
Always closes sessions if the application process is not likely to be used multiple times within the session idle time-out period (10 minutes by default).
Always keeps sessions open and reuses them when the application process is likely to be used multiple times within the session idle time-out period. It is important to reuse sessions that are not in use, as frequent logins add overhead to your process and slow it down.
Client applications must not reuse sessions that are in use, in other words, they must not submit several simultaneous requests using the same session.
Client applications must not send multiple requests simultaneously using the same session ID, rather, the client must wait for a response before sending a new request using the same session ID.
The client time-out on a single Web service call must be set to at least 10 minutes, so that the client does not time out when a request is still pending. For information about Web services sessions, see About Establishing and Managing the Web Services Session.
Session Pooling
Session pooling is another option for increasing the performance of your application further. Session pooling involves maintaining a list of active sessions on the client application. The client application must ensure that each session is active and valid (it must have a valid session ID) before using it in a request. The client application can determine whether the session is active based on the success of the login operation and the time that has passed since the session was used. If all active sessions are in use for pending Web service requests, add a new session to the pool.
You can use session pooling to improve performance in both a single-threaded or multithreaded application. In a single-threaded application, session pooling can avoid the unnecessary overhead of relogging into Oracle CRM On Demand for each request. In a multithreaded application session, you can use session pooling to run multiple requests at the same time.
API Calls
Whenever possible, it is recommended that queries be as specific as possible to reduce the number of records in the result set. You must restrict the fields returned by queries to only the fields that are required by your process.
Queries that involve related child objects (that is child objects that are top-level objects), or complex queries that involve criteria from both parent and related child objects, might perform better if they are separated into multiple requests.
The following are also recommended:
For Web Services v1.0 calls, use the child methods DeleteChild, InsertChild, and UpdateChild for child delete, insert, and update operations.
Whenever possible, store your company's unique identifiers in the external system ID field on objects.
Performance of the Update and Insert Methods Versus the InsertOrUpdate Method
If you use Web Services v1.0, designing your application to use the Insert and Update methods can result in an increase in throughput compared to using the InsertOrUpdate method. This is due to the additional business logic and SQL statements executed during the InsertOrUpdate operation to determine whether the submitted records match any existing records in the Oracle CRM On Demand database. The performance and throughput improvement might not be apparent at lower volumes, but high volume applications could benefit from the direct update and insert operation, which does not require the additional business logic to determine whether the records already exist.
Working with Attachments
For a number of record types, you can include attachments with Web services requests. If you add attachments, remember that:
Requests with large attachments perform more slowly than those with smaller attachments or no attachments. The maximum attachment size supported is 9MB.
Requests with many attachments perform more slowly than those with a single attachment or no attachments.
If you are adding the same attachment to multiple records, you can take advantage of a reuse facility for attachments, see Attaching a File to Multiple Records. In this way, you do not include the content for each record in the request, you use the ContentId on one record and reference that ContentId from other records. For more information about using attachments in Web Services On Demand, see Using Attachments with Web Services On Demand.
Querying Login History and User Usage
When you use the LoginHistoryQueryPage and UserUsageQueryPage methods, the queries must be as specific as possible, that is, you must not query for all records with every request. For example, you can narrow the search results by:
Querying for records owned by a specific UserID
Querying for records covering a period of time
For more information, see LoginHistoryQueryPage and UserUsageQueryPage.
Using the QueryPage Method
The following are best practices for using the QueryPage method and similar methods like MetadataChangeSummaryQueryPage and SalesProcessQueryPage:
If you intend to paginate through the snapshot of data returned by QueryPage, it is recommended to use a stateful Web services request. Using a stateless Web services request is not recommended because it can return the same record in multiple pages as you paginate though the results returned.
If you do use stateless QueryPage operations and then paginate through the snapshot of data returned, it is recommended that the QueryPage request uses sort criteria.
When formulating a query, use indexed fields, which are highlighted in green in the New List page in the Oracle CRM On Demand UI. Indexed fields are optimized for fast retrieval. As an example, use the indexed field ModifiedDateExt rather than the ModifiedDate field in QueryPage operations to provide better performance.
Specify the best operators to make queries faster. For example, use the equality (=) operator instead of the * wildcard. Other operators might provide some functional flexibility, but can severely impair performance. Therefore, you must only use other operators when absolutely required.
If filtering on a nonequality operator and not combining with any other filter criteria, change the sort order so that you are sorting on the same field that you are filtering.
Specify only fields that you are intending to use. Adding all fields or specifying fields that are not required impacts the response time or throughput.
If filtering on a custom field, make sure that the custom field is an indexed custom field. It might be required to migrate data from the existing field to the indexed custom field. For more information, see the section about Using Indexed Custom Fields.
Constrain filter criteria to return the least number of records possible (that is, queries must be as specific as possible).
If you must return many sorted records, make sure that you sort on an indexed field.
If you are using manager visibility (ViewMode= "Manager " or ViewMode= "EmployeeManager "), the query must contain an equality operator on an indexed field.
Avoid unnecessary use of attachments by accessing attachments through the Oracle CRM On Demand UI whenever possible.
Use the Web Services v2.0 API when querying for associated records, as Web Services v2.0 supports filtering and paging at the child level.
Avoid filtering on a calculated field because it impacts performance.
Use targeted searches and smaller page sizes for QueryPage operations to return less data in each request
For more information about the QueryPage method, see QueryPage, or QueryPage.
Querying Records with Foreign Key fields with the No Match Row Id Value
The No Match Row Id
value for a foreign key field indicates one of the following:
The foreign key refers to a nonexistent record.
The foreign key value is empty.
There are different cases for which No Match Row Id
is set for a foreign key field. For example, if you create a record without specifying a foreign key field in the insert operation, then the foreign key value is empty and is therefore set to No Match Row Id
. In this case, querying the record returns <ForeignKeyId>No Match Row Id</ForeignKeyId>
.
However, if you update a record and specify blank as the foreign key value, then it is set to empty. In this case, querying the record returns <ForeignKeyId></ForeignKeyId>
.
You must take the No Match Row Id value into consideration for foreign key fields when querying records. If you try to retrieve all records where the foreign key value is not null, then the query returns records including those with the No Match Row Id
value. Therefore, when querying a foreign key, the query criteria must include checking for null or not null as well as the No Match Row Id
value.
For example, when querying for accounts with primary contact associated to the account, the search criteria must specify that the PrimaryContactId is not null and not equal to No Match Row Id
, as shown in the following code sample:
<?xml version="1.0" encoding="utf-16" standalone="no"?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/ 2001/XMLSchema"> <soap:Body> <AccountQueryPage_Input xmlns="urn:crmondemand/ws/ecbs/account/10/2004"> <ListOfAccount> <Account searchspec="[PrimaryContactId] IS NOT NULL AND [PrimaryContactId] <> 'No Match Row Id'"> <AccountName/> <PrimaryContactId></PrimaryContactId> </Account> </ListOfAccount> </AccountQueryPage_Input> </soap:Body> </soap:Envelope>
Using Indexed Custom Fields
To optimize performance, you can use custom fields that have been indexed for specific record types. Indexed fields are special fields that improve the response time during the search process or sorting on a particular list. Indexed custom fields are preconfigured in the Oracle CRM On Demand database. You can change the labels on the indexed custom fields, but you cannot change the integration tags.
Indexed custom fields are prefixed with Indexed as a default.
Handling Bad Events in Integration Event Queues
Sometimes an integration event queue might contain an event that the client application cannot process. This situation can occur, for example, if a new custom field has been flagged as required but the client application that processes integration events has not been updated with a schema file that includes the integration tag for the new custom field.
Client applications cannot selectively delete events from the queue, so they must handle these events by performing the following steps:
In the GetEvents call, reduce the number of events retrieved by setting the EventCount argument to
1
.Use GetEvents to retrieve single events and process each of them until a bad event is identified.
If a parse error is encountered, save the bad event to a local folder or other location.
Delete the bad event from the queue using a DeleteEvents call with the LastEventId argument set to the ID of the bad event.
Continue processing events with the number of events set back to the default value.
Repeat steps 1 through 5 if more bad events are encountered.
For information about GetEvents and DeleteEvents, see GetEvents, and DeleteEvents respectively.
Best Practices for Integration Management
This topic describes best practices for system management when using client applications that make Web services calls.
Moving Customers Between Pods
To reduce the impact on customers when they move between pods (Oracle CRM On Demand instances), it is important that the server URL values for pods are parameterized, so that they can be changed easily.
Web services clients must be implemented in such a way that moving a customer to a new pod does not require any code changes within the Web services client. A best practice is to use an .ini file to store the server URL, so that changing the server value in the .ini file results in the Web services request being routed to the new Oracle CRM On Demand instance.
Web links, Web tabs, and custom Web applets that refer to Oracle CRM On Demand must be parameterized so that they can easily be redirected. A best practice is to pass the server URL or POD value (that is, the 3 letter pod identifier) so that it can be parsed from the URL, and the page being called can continue to interact with Oracle CRM On Demand through Web services.
Handling Outages
Outages can be due to:
Scheduled Maintenance Downtime. From time to time, Oracle CRM On Demand will have scheduled downtime when it is shut down to perform regular maintenance and upgrades. It is important for your client applications to be able to identify and respond correctly to this scenario.
Application Failures. If there is a failure within Oracle CRM On Demand, it is important for the client application to respond appropriately. Performing proper error handling and logging is extremely important because it will not only help you resolve issues on your own but, if necessary, help you engage with Oracle CRM On Demand Customer Support and provide them with critical information. For more information, see Handling Outages and Failures.
Maintaining SSL Certificates
Oracle CRM On Demand is accessible only through HTTPS and Oracle servers using Secure Sockets Layer (SSL) certificates issued by common certificate authorities (CA) such as Verisign. Approximately yearly these SSL certificates are renewed, so it is important that any clients (including browsers and integration clients) are configured to trust the root CA certificates and not the specific server certificates.
Occasionally the certificate authority might issue new root certificates or start issuing server SSL certificates to Oracle that use a different root or intermediate certificate. It is the responsibility of customers to ensure that their clients (browser or integration platform) are kept up to date with the latest root certificates from Verisign or others. See, for example, the Verisign Web site for details of how to update your client.