Professional Documents
Culture Documents
Caching
The client application must be browser-based and need to include the cache module library. Both Embedded Browser app and WebWork app shares the same design, only that the WebWork apps need to be configured to load the cache feature. Once the client application is loaded into the browser, any HTTP(s) request is controlled by the cache module. There are three ways for the cache client to interact with the server.
Standard caching: Cache responses based on request URL (use URL as ID). The replacement policy is based on e-tag header of the request and response.
Server pushing: The cache client describes to resources. When the resources changes, the server sends the changes to the cache client.
Piggy-back fetching: The server has a list of resources the cache client subscribed. Each time the client send a HTTP request to a resource, the server return the resource as well as changes on other subscribed resources.
Embedded Browser: A BrowserField is a UI component which can be added to Blackberry screen. For WebWork, applications run in a full screen embedded browser with some extra JavaScript libraries. There two ways to display content in the BrowserField. Request by URL: requestContent("http://google.ca/")
displayContent(connection, baseUrl) displayContent(html, baseUrl) We can also set properties of the BrowserField, one which is RequestListener. RequestListener interrupt any HTTP request made by the BrowserField. The following code shows how to create a BrowserField and RequestListener.
BrowserField browser=new BrowserField(); RequestListener rl=new RequestListener(browser); browser.getConfig().setProperty(BrowserFieldConfig.CONTROLLER, rl);
Request Listener: A RequestListener listens HTTP requests made by its associated embedded browser. It implements ProtocolController interface which enforce two method implementations. void handleNavigationRequest (BrowserFieldRequest request)
InputConnection
handleResourceRequest
(BrowserFieldRequest request)
Navigation request handler: the handleNavigationRequest method of the RequestListener handles navigation based HTTP requests, for example, when users click a link on a web page or change the browser location. The parameter (BrowserFieldRequest) of the method gives access to the HTTP requests. We can read the following content of the HTTP requests: post data, header, URL, protocol, but are only allowed to change the URL of the HTTP request. Example: redirect HTTP request to a static web page on the local file system
public void handleNavigationRequest(BrowserFieldRequest request) throws Exception { if(request.getURL().equals("http://www.google.ca/")){ //data is a byte array represents the HTML content, it need to loaded from cache browserField.displayContent(data, "text/html", request.getURL()); } }
Resource request handler: the handleResourceRequest method of the RequestListener handles resource based HTTP requests, for example, when web page contains image to be loaded or when an XMLHttpRequest is sent by the BrowserField. The parameter (BrowserFieldRequest) has the same properties of the parameter of handleNavigationRequest. However, the
handleResourceRequest requires a return type of InputConnection. The BrowserFieldResponse implements the InputConnection interface. We can create a BrowserFieldResponse from InputStream or a byte[].
Image Example: return a local image file instead of from the Internet
public InputConnection handleResourceRequest(BrowserFieldRequest request) throws Exception { FileConnection fconn = (FileConnection) Connector.open("file:///SDCard/UofSLogoLarge.png",Connector.READ); BrowserFieldResponse resp=new BrowserFieldResponse(request.getURL(), fconn.openInputStream(), "image/png"); return resp; }
public InputConnection handleResourceRequest(BrowserFieldRequest request) throws Exception { //jsonData is a byte array represents content with JSON format, it need to loaded from cache BrowserFieldResponse resp=new BrowserFieldResponse(request.getURL(), jsonData, "application/json"); return resp; }
Cache Manager: Cache manager determine whether the device is connected to the Internet and whether the local cached data is valid. It is not easy to determine whether Blackberry is connected to the Internet. To check the validity of the cached data, we use Etag in the HTTP header. If Etag is different, the cached data is replaced with the data received from Intenet.
Storage: There are two types of storage we use, file system and secure persistent storage. File system is good for non-private, large sized data, for example, HTML page and images. Resources on the file system can be identified by file name. Secure persistent storage automatically serializes objects and we can put encryption keys on the data. It is good for private and application specific data, for example objects and JSON data. Resources on the secure persistent storage are identified by a long type key. Example: read from and write to file
FileConnection fconn = (FileConnection) Connector.open("file:///SDCard/UofSLogoLarge.png",Connector.READ_WRITE); //read from DataInputStream DataInputStream in=fconn.openDataInputStream(); //write to DataOutputStream DataOutputStream out=fconn.openDataOutputStream();
JSONObject json; final long key=0x721f36727fd5102cL; PersistentObject p = PersistentStore.getPersistentObject(key); //save to persistent store if (json != null) { synchronized (p) { p.setContents(json); p.commit(); } } //read from persistent store synchronized (p) { json = (JSONObject) p.getContents(); }
HTTP client: The HTTP client responsible for sending HTTP request and receiving HTTP response. The following code shows how to create a HTTP conenction.
public static HttpConnection getHttpConnection(String url){ int[] preferredTransportTypes={TransportInfo.TRANSPORT_TCP_WIFI, TransportInfo.TRANSPORT_TCP_CELLULAR, TransportInfo.TRANSPORT_WAP2, TransportInfo.TRANSPORT_WAP,TransportInfo.TRANSPORT_MDS}; ConnectionFactory factory=new ConnectionFactory(); factory.setPreferredTransportTypes(preferredTransportTypes); ConnectionDescriptor conDescriptor=factory.getConnection(url); if(conDescriptor!=null){ httpCon=(HttpConnection)conDescriptor.getConnection(); return httpCon; } return null; }
The following code shows how to send HTTP request and read HTTP response content in Blackberry.
HttpConnection httpConn = AppConnection.getHttpConnection(url); int status = httpConn.getResponseCode(); if (status == HttpConnection.HTTP_OK) {
InputStream input = httpConn.openInputStream(); byte[] data = new byte[256]; int len = 0; int size = 0; StringBuffer raw = new StringBuffer(); while (-1 != (len = input.read(data))) { raw.append(new String(data, 0, len)); size += len; } } httpConn.close();
WebWork Configuration
Create a WebWork extension
This class initialized the extension feature. (Required) RequestListener is added on register.
public final class Cache implements WidgetExtension{ private final String[] featureList={"cache"}; public String[] getFeatureList() { return featureList; } public void loadFeature(String feature, String version, Document doc, ScriptEngine scriptEngine) throws Exception { if(feature.equals("cache")){ scriptEngine.addExtension("cache.test", new Test()); } } public void register(WidgetConfig widgetConfig, BrowserField browserField) { // set request listener here RequestListener rl=new RequestListener(browserField); browserField.getConfig().setProperty(BrowserFieldConfig.CONTROLLE R, rl); } public void unloadFeatures(Document doc) { } }
This class creates custom JavaScript API. (i.e. call cache.test.hello in JavaScript returns Hello )
public class Test extends Scriptable{ private final String LOAD_CACHE="hello"; public Loader(){ } public Object getField(String name) throws Exception { if(name.equals(LOAD_CACHE)){ return "Hello"; } return super.getField(name); } }
<?xml version="1.0" encoding="UTF-8"?> <widget xmlns="http://www.w3.org/ns/widgets" xmlns:rim="http://www.blackberry.com/ns/widgets" version="1.0.0.0"> <name>CacheModule_widget</name> <feature id="cache" required="true" version="1.0.0.0"/> <access subdomains="true" uri="*" /> <content src="http://geekberry.co.uk/"/> </widget>