CS569 Selected Topics in Software Engineering Spring 2012 Mobile: Accessing remote data Integrating remote content into native mobile apps 1. User opens mobile app 2. App calls up the server, sends URL 3. Server figures out how to handle request – Maybe just sends a file back – Maybe calls some custom code (JSP or servlet) 4. Server sends HTML/XML/JSON to app 5. App interprets data 6. User interacts with app and is happy Big picture App Server Servlet Data store URL Request Query, etc Data HTML/XML/JSON HTML/XML/JSON Zooming into the app App UI App JS UI event Server Servlet Data store URL Request Query, etc Data HTML/XML/JSON HTML/XML/JSON updates Very simple example: just get html var url = "http://www.google.com/"; var client = Ti.Network.createHTTPClient({ // function called when the response data is available onload : function(e) { alert('success:'+this.responseText); }, // function called when an error occurs, including a timeout onerror : function(e) { alert('error'+e.error); }, timeout : 5000 /* in milliseconds */ }); 1. Make a servlet that client.open("GET", url); returns some HTML client.send(); 2. Hit the URL Ti.UI.createWindow().open(); Debugging iOS apps locally on a Mac iOS apps in simulator often can’t access GAE. Here’s a hideous workaround. 1. 2. 3. 4. 5. 6. 7. 8. 9. Open Terminal (spotlight > Terminal) Map 127.0.0.1 to a fake hostname vi /etc/hosts arrow key down to the end of the document, type letter “a” to append add the line: 127.0.0.1 www.cs569.com to save, type: escape :w! escape :q Download Burp proxy from http://portswigger.net/burp/downloadfree.html Unzip Burp proxy, move files some place safe Set Burp as your Mac’s proxy (Apple Symbol in top left corner > System preferences > Advanced > Proxies; check both Web Proxy and Secure Web Proxy, set the ip address to 127.0.0.1 and port to 8080) Go to Terminal and start up Burp cd wherever you saved those Burp files java -jar -Xmx2g burpsuite_v1.4.01.jar Now that Burp is running, go to your regular browser and try to hit http://www.cs569.com:8888/_ah/admin By default, Burp will block access. Go to the Burp window, proxy tab, and click “Intercept” button to turn intercept off. Now the hostname should nicely map to your GAE admin console In your Titanium code, you should now be able to successfully retrieve data from GAE through the fake hostname. Debugging Android apps locally • Very simple: just use 10.0.2.2 in your app to refer to your own computer Example: Getting HTML from GAE running locally (iOS) <%= (1+1) %> var url = "http://www.cs569.com:8888/lectures/mobileremote/test1.jsp"; var client = Ti.Network.createHTTPClient({ // function called when the response data is available onload : function(e) { alert('success:'+this.responseText); }, // function called when an error occurs, including a timeout onerror : function(e) { alert('error'+e.error); 1. Make a servlet that }, returns some HTML timeout : 5000 /* in milliseconds */ 2. In iOS app, create an http }); client, with specified client.open("GET", url); “onload” and “onerror” client.send(); handlers. 3. Open, send request. Ti.UI.createWindow().open(); Getting fancier: posting data just like a browser would you sent me a total of <%= Integer.parseInt(request.getParameter("a")) + Integer.parseInt(request.getParameter("b")) %> var url = "http://www.cs569.com:8888/lectures/mobileremote/test2.jsp"; var client = Ti.Network.createHTTPClient({ // function called when the response data is available onload : function(e) { alert('success:'+this.responseText); }, // function called when an error occurs, including a timeout onerror : function(e) { 1. Make a servlet that alert('error'+e.error); returns some HTML }, timeout : 5000 /* in milliseconds */ 2. In iOS app, create an http }); client, with specified client.open("POST", url); “onload” and “onerror” client.send({a:1,b:2}); Ti.UI.createWindow().open(); handlers. 3. Open, send POST request with parameters. GET vs POST • “idempotent operation”: means that an operation can be repeated (or not) without any side-effects – Idempotent operations are safe to repeat, or not • GET: use only for idempotent operations – Such as retrieving data – GET requests might be cached on the network or repeated within the network multiple times or performed automatically (e.g., by search engines) • POST: use for all other operations Now you have some options… … for what your servlet does with the data… • Use it for some computations • Store it in the datastore • Forward it to another server (e.g., webservice) And some options for what to send back… • HTML – Pros: No need to write a separate servlet – Cons: Very inefficient to send and parse HTML • XML – Pros: Compatible with many other systems – Cons: Moderately inefficient to send and parse • JSON – Pros: Highly efficient to send and parse – Cons: More work for you, in many cases JSP for sending back XML <% // Note: there can be NO blank space at the top of the page // The header (below) MUST be the first thing in the document response.setContentType("text/xml"); out.write("<?xml version=\"1.0\" ?>"); %> <mydocument> <% for (int i = 0; i < 10; i++) out.write("<myelement cnt=\""+i+"\" />"); %> </mydocument> JS for reading XML in Titanium … onload : function(e) { var xml = this.responseXML; var els = xml.getElementsByTagName("myelement"); var sum = 0; for (var i = 0; i < els.length; i++) { var vl = parseFloat(els.item(i).getAttribute("cnt")); if (!isNaN(vl) && vl > 0) sum += vl; } alert("the sum is "+sum); }, … Welcome to JSON • “JavaScript Object Notation” – looks very similar to how objects are defined in JS • However, it’s just a notation, and it’s supported in other languages, too. • Example: {"title":"blah blah blah", "id":110,"emails":null, "notes":"", "somechildobjct":{"nm":"rufus"} } JS for reading JSON in Titanium … onload : function(e) { Ti.API.info("Received text: " + this.responseText); var json = null; try { json = JSON.parse(this.responseText); alert('success'+json); } catch (err) { alert('unable to parse json:'+this.responseText); } }, … Parsing JSON on the server is a little more of a hassle • Import the JSON Simple library – 1. Download JAR from http://code.google.com/p/json-simple/ – 2. Drag+drop JAR into war/WEB-INF/lib/ – 3. Right-click project > Build Path > Add libraries > User Library > User Libraries > New > Add JARs • Instantiate structured object with the library, serialize it to client (see example on next slide) Generating JSON object from server <%@ page import="org.json.simple.JSONObject" %> … // load some data from the data store JSONObject json = new JSONObject(); json.put(”id", data.someValue()); json.put("title", data.someOtherValue()); json.put("emails", data.someEmailProperty()); json.put("notes", whatever()); JSONObject someSubObject = new JSONObject(); someSubObject.put("blahblah",111222); json.put("psomeobj", someSubObject ); out.write(json.toString()); Other features of the JSON simple library • Generating JSON arrays {"myarr":[1,2,4,6,8]} (Can be a property, or a top-level object) • Parsing string back to JSON object – Including partial parse: you can start a parse and then pause or cancel parsing depending on what you find in the JSON stream Some cautions and caveats: Reliability • Mobile network connections are unreliable – You need exception handlers – You can proactively retrieve data and cache it so it’s available later, even if no network is present – You can buffer data that is destined for the server, and flush it later on Some cautions and caveats: Usability • Mobile network connections are slow – If you do network operations synchronously, you will lock up the user interface – Do everything you can to perform network operations asynchronously (as I have shown you) – Try to minimize the number of times the user has to wait for network operations to complete • E.g., do operations in background while user can continue working in the user interface • Another example: have the user log in just once, and with the option to stay logged in for a week Some cautions and caveats: Performance • Mobile network connections are slow (contd) – Try to avoid repeatedly downloading the same data or code • E.g., display the user interface and only transmit data; don’t repeatedly download the UI (as in a web page) – Avoid transmitting data unnecessarily • E.g., define your JSP to accept a “verbose” parameter that tells how much of a dataset should be sent – Minimize network roundtrips Some cautions and caveats: Security • Mobile network connections are insecure – Consider using https: all data are encrypted • Although this does require more CPU and does impose more network overhead – Consider selectively encrypting some parameters • Ditto, but not quite as bad; could be a good compromise between https and no encryption at all – Be sure to encrypt any usernames or passwords that you store on the user’s device! I’ll return to these caveats with more concrete advice • In the mean time… – Get the “install and configure” part of your mobile How-To finished this week – Take a look at the pure-JS libraries available for retrieving data in a web application (i.e., outside of a mobile app) • A.k.a. “AJAX” (Asynchronous Javascript And XML), though the data do not need to be in XML format. • http://www.w3schools.com/ajax/ajax_intro.asp