You are on page 1of 11

Blackberry Cache Module

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.

Cache Module Architecture

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/")

Load content as bytes: displayContent(data, contentType, baseUrl)

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)

The following code shows a RequestListener class.


public class RequestListener extends ProtocolController{ private BrowserField browserField; public RequestListener(BrowserField browserField){ super(browserField); this.browserField=browserField; } public void handleNavigationRequest(BrowserFieldRequest request) throws Exception { } public InputConnection handleResourceRequest(BrowserFieldRequest request) throws Exception { return super.handleResourceRequest(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/")){ request.setURL("file:///SDCard/index.html"); } }

Example: load cached data into the BrowserField

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; }

XMLHttpRequest Example: return JSON data from cache

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();

Example: read from and write to persistent store

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); } }

Create a library.xml file at the src folder. (Required)


<?xml version="1.0" encoding="UTF-8"?> <library> <extension> <entryClass>usask.madmuc.andy.cache.ext.Cache</entryClass> <features> <feature id="cache" version="1.0.0">Cache widget extension</feature> <access subdomains="true" uri="*"/> </features> </extension> </library>

Finally, package the java source files into a jar file.

To add a custom JavaScript library to WebWork applications


Add the jar file into ext folder

Add feature into the config.xml file

<?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>

Email Push on Blackberry


On the server side, send email to Gmail account using Java standard email library.
private void postMail(String recipients[], String subject, String message, String from) throws MessagingException { final String SMTP_HOST_NAME = "smtp.gmail.com"; final int SMTP_HOST_PORT = 465; final String SMTP_AUTH_USER = "madmuc@gmail.com"; final String SMTP_AUTH_PWD = "**password**"; boolean debug = false; //Set the host smtp address Properties props = new Properties(); props.put("mail.smtp.host", SMTP_HOST_NAME); props.put("mail.transport.protocol", "smtps"); props.put("mail.smtps.auth", "true"); // props.put("mail.smtps.quitwait", "false"); // create some properties and get the default Session Session session = Session.getDefaultInstance(props, null); Transport transport = session.getTransport(); session.setDebug(debug); // create a message Message msg = new MimeMessage(session); // set the from and to address InternetAddress addressFrom = new InternetAddress(from); msg.setFrom(addressFrom); InternetAddress[] addressTo = new InternetAddress[recipients.length]; for (int i = 0; i < recipients.length; i++) { addressTo[i] = new InternetAddress(recipients[i]); } msg.setRecipients(Message.RecipientType.TO, addressTo); // Setting the Subject and Content Type msg.setSubject(subject); msg.setContent(message, "text/plain");

transport.connect(SMTP_HOST_NAME, SMTP_HOST_PORT, SMTP_AUTH_USER, SMTP_AUTH_PWD); transport.sendMessage(msg, msg.getRecipients(Message.RecipientType.TO)); transport.close(); }

On the client side, intercept when an email is received.


public class MailListener implements FolderListener { public MailListener() { //add the listener to the mail folder Session.getDefaultInstance().getStore().addFolderListener(this); } //when message is received public void messagesAdded(FolderEvent e) { if(e.getMessage().getSubject()!=null){ //do something here } } public void messagesRemoved(FolderEvent arg0) { } }

You might also like