Developer

Technical Cache for Online Applications

The technical cache extends the Online Store and OData APIs to enhance online applications in cases where the application is occasionally offline by: optimizing application-to-server communication for online stores, performing conditional HTTP or OData requests to optimize network bandwidth utilization for cached responses from previous OData requests, and using on-device cached content to improve application performance.

Operational States

OData API requests can be either asynchronous (execute in the background), or synchronous (operate in the foreground, blocking any other processes). The technical cache is enabled when the online store sends asynchronous requests, and must be enabled explicitly by the application developer when opening the online store.

An offline store can only be opened with a disabled technical cache. A technical cache in combination with the offline store adds no benefit, since the offline store is considered a cache. Passive mode can be activated only on a store for which a technical cache is enabled. If the technical cache is disabled or for an offline store, a request to switch to passive mode throws an exception.

Online Store – Asynchronous OData Request Behavior

  • Active mode Store behavior for asynchronous requests with an enabled cache in active mode is that the requestCacheResponse callback is called independently if the payload is cached for the request.

    In active mode OnlineOdataStore uses the technical cache for optimization. In each request OnlineOdataStore notifies the application about the cached response within ODataRequestListener.requestCacheResponse(ODataRequestExecution) callback. Then OnlineODataStore sends the request to the server. When the server response arrives it notifies the application about the server response within ODataRequestListener.requestServerResponse(ODataRequestExecution) callback.

    Callback sequence for a successful request:
    1. requestStarted (Status = = “Initialized”)
    2. requestCacheResponse (Status = = “InProgress”)
    3. requestServerResponse (Status = = “InProgress”)
    4. requestFinished (Status = = “Completed”)
    Callback sequence for a failed request:
    1. requestStarted (Status = = “Initialized”)
    2. requestCacheResponse (Status = = “InProgress”)
    3. requestFailed (Status = = “Failed”)
    4. requestFinished (Status = = “Failed”)

    The cache response must differentiate between unavailable cache content and empty cache content. The application must be able to identify whether the request has never been executed (or has been removed from the cache) or if it was executed earlier and the server responded with an empty payload. A null value for ODataResponse indicates nonexistent cache content.

    The ODataResponse object in the requestFinished callback is the same as within the requestServerResponse or requestFailed callback.

    The payload of the ODataResponse within the requestServerResponse callback is stored in the cache. A subsequent request returns the identical payload within the requestCacheResponse. The previous cached payload is removed from the cache. The cache does not keep historical data from previous requests. If the request fails, the cache content is modified.

  • Passive mode For asynchronous requests with an enabled cache in passive mode, the requestServerResponse callback is not triggered.

    In passive mode OnlineOdataStore uses only the cache data. In this case there is no network round-trip. Typically this mode is used when there is no network coverage. In each request the OnlineOdataStore notifies the application of the cached response within ODataRequestListener.requestCacheResponse(ODataRequestExecution) callback. There is no request to the server.

    Callback sequence for a successful request:
    1. requestStarted (Status = = “Initialized”)
    2. requestCacheResponse (Status = = “InProgress”)
    3. requestFinished (Status = = “Completed”)
    Callback sequence for a failed request:
    1. requestStarted (Status = = “Initialized”)
    2. requestFailed (Status = = “Failed”)
    3. requestFinished (Status = = “Failed”)

    Missing cache content for an OData request is not considered a failure (the response's payload is null).

    In passive mode, the library does not alter the content of the cache.

Summary of Callbacks

This table summarizes the callbacks for:
  • A single read request with useCache=true
  • A batch including at least one read request with useCache=true
Mode Store state Cache enabled and opened Cache enabled but closed Cache disabled
Active Open cacheResponse /serverResponse serverResponse serverResponse
Active Close Failure Failure Failure
Passive Open cacheResponse Failure N/A
Passive Close Failure Failure N/A
This table summarizes the callbacks for:
  • A single CUD request
  • A single read request with useCache=false
  • A batch including only CUDs or read requests with useCache=false
Mode Store state Cache enabled and opened Cache enabled but closed Cache disabled
Active Open serverResponse serverResponse serverResponse
Active Close Failure Failure Failure
Passive Open Failure Failure N/A
Passive Close Failure Failure N/A

Unsupported Features

If an application requires unsupported features, use an offline store:
  • Queries in cached content: a response is associated to a particular request (including all parameters) and is treated as an unbreakable unit. Use cached content only if the request URL of a second request is (literally) identical.
  • CUD operations

The offline store does not use the technical cache. The OData Offline Store API does not provide a setting to open a store with cache enabled.

Example

This iOS sample code illustrates initializing and opening an online store that uses the technical cache.
// Open an online store
-(void) openOnlineStore {
    
    if (!existingOnlineStore)
    {
        //* Instantiate Cache
        SODataOnlineStoreOptions* options = [[SODataOnlineStoreOptions alloc]init];
        options.useCache = TRUE;
        options.cacheEncryptionKey = @“cacheEncrytionKey";
    
        SODataOnlineStore* onlineStore = [[SODataOnlineStore alloc] initWithURL:[NSURL URLWithString:endpointUrl]  httpConversationManager:logonHandler.httpConvManager options:options];
    
        [onlineStore setOnlineStoreDelegate:self];
        existingOnlineStore = onlineStore;
    }
    
    if (![(existingOnlineStore isOpen])
    {
    
        NSError *error = nil;
        BOOL success = [existingOnlineStore openStoreWithError:&error];
        if (!success)
        {
            NSLog(@"Failed to open store: %@", [error description]);
        }
    } else
    {
        // Store is already open , do any processing needed after store open
    }
}

#pragma mark - SODataOnlineStoreDelegates

-(void)onlineStoreOpenFinished:(SODataOnlineStore *)store{
   
// Do any processing needed after store open
    
}

-(void)onlineStoreOpenFailed:(SODataOnlineStore *)store error:(NSError *)error{

// Store open failed
    
   }
Some general points to keep in mind:
  1. The cache stores the result of the previous GET request based on the endpoint. As the newer cache data gets added, the older data is deleted based on the settings for cache size. For example:
    1. First get call with urlendpoint1 (cache is empty initially)

      requestserverresponse call returns the payload and the cache is populated with urlendpoint1 data.

    2. First get call with urlendpoint2 (cache is empty initially)

      requestserverresponse call populates the cache with urlendpoint2 data.

    3. get call with urlendpoint1 (requestCacheResponse retireves data from cache)

      requestserverresponse has the latest data from the server.

    4. get call with urlendpoint2 (requestCacheResponse retireves data from cache)

      requestserverresponse has the latest data from the server.

      The data in the cache is persisted. Without connectivity in passive mode you can read from the cache from the requestCacheResponse callback.

  2. SAP recommends that you close the cache when the app goes to the background, but do not close the store unless it is no longer required. When the app returns to the foreground you can reopen the cache with the encryption key, which is preferable from a security point of view.
  3. Close the cache before calling reset on the cache.
  4. Do not call init on an open store. That is, once you have initialized and opened the store, do not initalize the store again.
  5. If the store was previously opened, you can use it without opening it again. But in this case there is no openStoreFinished callback (as it is only for openStoreWithError), so whatever you do in your application you must trigger the execution elsewhere.