Resource Manager

The ResourceManager provides functionality which allows users to store and retrieve data. The data, which is stored on the service node, can be anything that the service can copy as a ByteArray. This feature is commonly used in a collaborative session, when multiple users are connected to the same PureWeb session.

Since the SDK is designed to provide data security and keep clients very thin, the link to the resources is temporary: stored data is only available as long as the application session remains active.

 

The Resource Manager is primarily intended to facilitate the transfer service-side data to the client.

To transfer client-side data to the service, you would go a different route. Best practice will depend on the amount of data:

  • For a small amount of data, it may be possible to use commands: convert the data to a base64 encoded string, and pass it to the service application in the parameters object of the command.
  • For larger amounts of data, it may be best to use a different tool or mechanism such as side loading using FTP/SCP or cloud storage.

Overview

Data storage and retrieval is based on the unique identifier (GUID) key which the Resource Manager's store function automatically assigns to each resource:

  • In your service, you can define which GUID key to send to which client, and hence manage which clients have access to what files.
  • All a client needs to retrieve a resource is the value for the GUID key; data retrieval is done using the RetrieveObject method.
  • Clients can construct a URL from the GUID key and use this URL to access the resource directly (in iOS, Java and Android clients), or with a web browser; this is achieved by using the GetResourceURL method.

It is possible for the service-side store function to save the same data in several different formats. This would be useful, for instance, to handle operating system differences. Consider for example the case of a collaborative text editing application. When saving the file in the Resource Manager, the service would save it in two different formats, let’s say a Windows-targeted .docx file and a .pages file for iOS-based clients. Each file format would be assigned its own GUID key; the key for the .docx files would be sent to the Windows clients, and the key to the .pages would be sent to the iOS-based clients.

Like most other communications between the service and the client, you can choose to use either commands or application state to provide to the clients the GUIDs associated with the stored data. With commands, the response only goes back to the client session that sent the command; writing the GUID in a descriptive path of application state allows the service to make the data available simultaneously to any and all clients.

The screen capture example below illustrates an implementation of the Resource Manager using commands.

  The Resource Manager currently has a 2 GB limit, due to how the RetrieveObject method in the various APIs retrieves the resources.

Example - Screen Captures

This example uses a C++ service and an HTML5 client.

To try this example yourself, edit the source code for the Scribble sample application. The necessary files are in the server installed directory:

  • Service: [installed_location]\SDK\Samples\Scribble\ScribbleAppCpp
  • Client: [installed_location]\SDK\Samples\Scribble\ScribbleClientHTML5

Service Code (Storing Data)

Assuming that the service will receive a command from the client application to save a screen capture (see client application code example further down), the service will first need a command handler, as shown below. (In the Scribble sample application, add the following code to the constructor in the ScribbleView.cpp file.):

CScribbleApp::StateManager().CommandManager().AddUiHandler("Save", Bind(this, &CScribbleView::OnExecuteSave));

This handler responds to the command Save by executing the OnExecuteSave method, shown below (add this code to the bottom of the file).

void CScribbleView::OnExecuteSave(CSI::Guid sessionId, CSI::Typeless command, CSI::Typeless response)
{
    PureWeb::Image image(m_pPixelBits, m_Width, m_Height, PureWeb::PixelFormat::Bgr24, PureWeb::ScanLineOrder::TopDown, 4);
    ByteArray jpeg = PureWeb::JpegEncoder::JpegCompress(image, 80);
    ContentInfo content("image/jpeg", jpeg.AsByteArray());
    Guid key = CScribbleApp::StateManager().ResourceManager().Store(content);
    response["ResourceKey"] = key;
}

This code:

  • creates an image given the current view’s pixel bits and dimensions (line 3) -- the variables m_pPixilBits, m_Width and m_Height are defined elsewhere in the Scribble sample code
  • converts the image into a JPEG (line 4),
  • packs the JPEG into a ContentInfo object (line 5),
  • stores the ContentInfo object into the application’s Resource Manager and returns a GUID (line 6),
  • returns the GUID as ResourceKey to the calling application (line 7).

Next, add a declaration of this new method in the header file (ScribbleView.h):

void OnExecuteSave(CSI::Guid sessionId, CSI::Typeless command, CSI::Typeless response);

Client Code (Retrieving Data)

On the client side, first add a button which, when clicked, will run the method to request a screen capture of the service application’s view; in this example, the method is called onSaveScreenShotClicked.

To create the button in the sample HTML5 client, add the following line in the file ScribbleApp.html.

<button onClick="onSaveScreenShotClicked();">Save Screenshot</button>
<img id="screenshotImage"/>

Then, add the onSaveScreenShotClicked method to the ScribbleApp.js file. In this example, the code includes both the RetrieveObject and the GetResourceURL methods, for illustration purposes. The RetrieveObject method would be used internally by the program and does not display the retrieved resource to the end user. However, with the GetResourceURL method the user will be able to see the saved screen capture when the program runs:

onSaveScreenShotClicked = function() {            
    pureweb.getClient().queueCommand('Save', null, onSaveScreenShotClickedCallback);
};

onSaveScreenShotClickedCallback = function(sender, args) {
    var key = pureweb.xml.XmlUtility.getText(
        {parent: args.getResponse(), childPath: '/ResourceKey'});

    var resourceUrl = pureweb.getClient().getResourceUrl(key);
    window.prompt("Here is your saved image" ,resourceUrl);
    getScreenshot(resourceUrl);
};

getScreenshot = function(resourceUrl){
    var webClient = pureweb.getClient();
    if (webClient.supportsRetrieveObject()) {
        webClient.retrieveObject(key,
            function(obj, err) { 
                if (obj){
                    document.getElementById('screenshotImage').src = window.URL.createObjectURL(obj);	
                }else{
                    alert('Cannot retrieve screenshot: ' + err); 
                } 
            }
        );
    } else{ 
        document.getElementById('screenshotImage').src = resourceUrl;	
    }
};

After editing the sample Scribble application, when it runs next, try the new screen capture functionality:

There will be a new Save Screenshot button in the HTML5 client. Click it; the application will open a view on top of the current window, with the URL to the file. Copy and paste this link in a new window to retrieve the screen capture; this will work as long as the session remains active. Close the new view.