<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Adrian Smith's Blog</title>
	
	<link>http://www.17od.com</link>
	<description />
	<lastBuildDate>Mon, 09 Aug 2010 18:07:50 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/AdrianSmithsBlog" /><feedburner:info uri="adriansmithsblog" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>UPM for Android 1.2 Released</title>
		<link>http://feedproxy.google.com/~r/AdrianSmithsBlog/~3/rX7X7HFkX3o/</link>
		<comments>http://www.17od.com/2010/08/09/upm-for-android-1-2-released/#comments</comments>
		<pubDate>Mon, 09 Aug 2010 18:07:50 +0000</pubDate>
		<dc:creator>Adrian</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[android]]></category>
		<category><![CDATA[upm]]></category>

		<guid isPermaLink="false">http://www.17od.com/?p=351</guid>
		<description><![CDATA[Universal Password Manager for Android 1.2 has been released. The easiest way to install it is from the Android Market. Alternatively the apk can be downloaded from SourceForge. The source is also available there. From the release notes&#8230; Long-clicking on an account now brings up a context menu allowing you to copy username, copy password, [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://upm.sourceforge.net">Universal Password Manager</a> for Android 1.2 has been released. The easiest way to install it is from the Android Market. Alternatively the apk can be downloaded from <a href="https://sourceforge.net/projects/upm/files/UPM/upm-android-1.2/">SourceForge</a>. The source is also available there.</p>
<p>From the release notes&#8230;</p>
<ul>
<li>Long-clicking on an account now brings up a context menu allowing you to copy username, copy password, launch URL or edit account</li>
<li>Added the ability to trust self signed certificates and certificates that have a different Common Name to the website hostname</li>
<li>Increased the font size on the Account Details activity</li>
<li>Fixed a bug on the main Accounts page so that it recovers gracefully when the database is closed unexpectedly</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.17od.com/2010/08/09/upm-for-android-1-2-released/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.17od.com/2010/08/09/upm-for-android-1-2-released/</feedburner:origLink></item>
		<item>
		<title>Calling RESTful Recess Services using Javascript and JSON</title>
		<link>http://feedproxy.google.com/~r/AdrianSmithsBlog/~3/eRRUiIxTKwk/</link>
		<comments>http://www.17od.com/2010/08/02/calling-restful-recess-services-using-javascript-and-json/#comments</comments>
		<pubDate>Mon, 02 Aug 2010 19:25:04 +0000</pubDate>
		<dc:creator>Adrian</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[recessframework]]></category>
		<category><![CDATA[restful]]></category>
		<category><![CDATA[yui]]></category>

		<guid isPermaLink="false">http://www.17od.com/?p=332</guid>
		<description><![CDATA[As part of a proof of concept I was carrying recently I wanted to deploy and call a simple REST service from Javascript. Ultimately I&#8217;ll probably use a Java based framework like Restlet (I&#8217;ll be deploying to Google App Engine) but in the meantime the Recess framework proved very useful. Using it&#8217;s GUI based tools [...]]]></description>
			<content:encoded><![CDATA[<p>As part of a proof of concept I was carrying recently I wanted to deploy and call a simple <a href="http://en.wikipedia.org/wiki/Representational_State_Transfer#RESTful_web_services">REST service</a> from Javascript. Ultimately I&#8217;ll probably use a Java based framework like <a href="http://www.restlet.org/">Restlet</a> (I&#8217;ll be deploying to <a href="http://code.google.com/appengine/">Google App Engine</a>) but in the meantime the <a href="http://www.recessframework.org/">Recess</a> framework proved very useful. Using it&#8217;s GUI based tools it&#8217;s very easy to setup a persistent data model and expose it as a REST service.</p>
<p>On the client side I used the <a href="http://developer.yahoo.com/yui/3/">YUI</a> Javascript framework and <a href="http://www.json.org/">JSON</a> as the data interchange format. There didn&#8217;t seem to be a direct example of doing this on the Recess website here&#8217;s what I came up with.</p>
<p>The only Recess specific requirement is that the Json View is registered on your application controller. More info on views <a href="http://www.recessframework.org/book/html/ch10s02.html">here</a>.</p>
<pre name="code" class="php">
!RespondsWith Layouts, Json
</pre>
<p>Here&#8217;s Javascript code to create a object of type Entry. The object has two attributes, &#8220;date&#8221; and &#8220;data&#8221;. </p>
<pre name="code" class="javascript">
Y.io("/recess/myjournal/entry/", {
  method: "POST",
  data: {
    "entry[date][day]": Y.one("#entryDay").get("value"),
    "entry[date][month]": Y.one("#entryMonth").get("value"),
    "entry[date][year]": Y.one("#entryYear").get("value"),
    "entry[data]": Y.one("#entryText").get("value")
  },
  on: {
    success: function(transactionid, response, arguments) {
      alert("entry successfully added");
    },
    failure: function(transactionid, response, arguments) {
      alert("add entry failed: " + response.responseText);
    }
  }
});
</pre>
<p>For anyone interested in seeing this code in context here&#8217;s the page it&#8217;s used on. Remember this is just some simple proof of concept stuff so it&#8217;s very rough and ready.</p>
<pre name="code" class="javascript">
&lt;html&gt;
  &lt;head&gt;
    &lt;title&gt;My Journal&lt;/title&gt;
    &lt;script type="text/javascript" charset="utf-8" src="http://yui.yahooapis.com/3.1.1/build/yui/yui-min.js"&gt;&lt;/script&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;h2&gt;Entries&lt;/h2&gt;
    &lt;ul id="entriesList"&gt;
    &lt;/ul&gt;

    &lt;form id="newEntryForm" style="display: none"&gt;
      &lt;input id="entryDay" type="text" size="2" maxlength="2"&gt;
      &lt;select id="entryMonth"&gt;
        &lt;option value="1"&gt;Jan&lt;/option&gt;
        &lt;option value="2"&gt;Feb&lt;/option&gt;
        &lt;option value="3"&gt;Mar&lt;/option&gt;
        &lt;option value="4"&gt;Apr&lt;/option&gt;
        &lt;option value="5"&gt;May&lt;/option&gt;
        &lt;option value="6"&gt;June&lt;/option&gt;
        &lt;option value="7"&gt;July&lt;/option&gt;
        &lt;option value="8"&gt;Aug&lt;/option&gt;
        &lt;option value="9"&gt;Sept&lt;/option&gt;
        &lt;option value="10"&gt;Oct&lt;/option&gt;
        &lt;option value="11"&gt;Nov&lt;/option&gt;
        &lt;option value="12"&gt;Dec&lt;/option&gt;  
      &lt;/select&gt;
      &lt;input id="entryYear" type="text" size="2" maxlength="4"&gt;
      &lt;br&gt;
      &lt;textarea id="entryText" rows="10" cols="20"&gt;&lt;/textarea&gt;
      &lt;br&gt;
      &lt;input id="cancelAddButton" type="button" value="Cancel"&gt;
      &lt;input id="saveEntryButton" type="button" value="Save"&gt;
    &lt;/form&gt;

    &lt;form&gt;
      &lt;input id="refreshButton" type="button" value="Refresh" disabled="true"&gt;
      &lt;input id="addButton" type="button" value="Add"&gt;
    &lt;/form&gt;

    &lt;script&gt;
      YUI().use("node", "io", "json", "datatype-date", "querystring-stringify-simple", function(Y) {
        // Add an entry to list
        var addEntryToList = function(entryDate) {
          var listNode = Y.one("#entriesList");
          var date = Y.DataType.Date.format(entryDate, {format: "%Y-%m-%d"});
          listNode.append("&lt;li&gt;" + date + "&lt;/li&gt;");
        };

        // Retrieve entries and add them to the list
        var populateEntriesList = function() {
          Y.one("#refreshButton").set("disabled", true);

          Y.io("/recess/myjournal/entry.json", {
            method: "GET",
            on: {
              success: function(transactionid, response, arguments) {
                var listNode = Y.one("#entriesList");
                listNode.get("children").remove();

                var entries = Y.JSON.parse(response.responseText);

                Y.each(entries.entrySet, function(entry, index, array) {
                  // The date coming from the server will by in seconds. Date() expects milliseconds so * by 1000. 
                  addEntryToList(new Date(entry.date * 1000));
                });
              },
              failure: function(transactionid, response, arguments) {
                alert("get entries failed: " + response.responseText);
              },
              end: function(transactionid, arguments) {
                Y.one("#refreshButton").set("disabled", false);
              }
            }
          });
        };

        var showAddEntryControls = function() {
          Y.one("#newEntryForm").setStyle("display", "block");
        };

        var saveEntry = function() {
          Y.io("/recess/myjournal/entry/", {
            method: "POST",
            data: {
              "entry[date][day]": Y.one("#entryDay").get("value"),
              "entry[date][month]": Y.one("#entryMonth").get("value"),
              "entry[date][year]": Y.one("#entryYear").get("value"),
              "entry[data]": Y.one("#entryText").get("value")
            },
            on: {
              success: function(transactionid, response, arguments) {
                var entryDate = new Date(
                  Y.one("#entryYear").get("value"), 
                  Y.one("#entryMonth").get("value") - 1,
                  Y.one("#entryDay").get("value")
                );
                addEntryToList(entryDate);
              },
              failure: function(transactionid, response, arguments) {
                alert("add entry failed: " + response.responseText);
              },
              end: function(transactionid, arguments) {
                Y.one("#newEntryForm").setStyle("display", "none");
              }
            }
          });
        };

        var cancelAddEntry = function() {
          Y.one("#newEntryForm").setStyle("display", "none");
        };

        Y.on("available", populateEntriesList, "#entriesList");
        Y.one("#refreshButton").on("click", populateEntriesList);
        Y.one("#addButton").on("click", showAddEntryControls);
        Y.one("#cancelAddButton").on("click", cancelAddEntry);
        Y.one("#saveEntryButton").on("click", saveEntry);
      });
    &lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;
</code>
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.17od.com/2010/08/02/calling-restful-recess-services-using-javascript-and-json/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.17od.com/2010/08/02/calling-restful-recess-services-using-javascript-and-json/</feedburner:origLink></item>
		<item>
		<title>Amazon Prices for Ireland – Chrome Extension</title>
		<link>http://feedproxy.google.com/~r/AdrianSmithsBlog/~3/lHuBhvw2TaA/</link>
		<comments>http://www.17od.com/2010/07/01/amazon-prices-for-ireland-chrome-extension/#comments</comments>
		<pubDate>Thu, 01 Jul 2010 07:37:26 +0000</pubDate>
		<dc:creator>Adrian</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[amazon]]></category>
		<category><![CDATA[chrome]]></category>

		<guid isPermaLink="false">http://www.17od.com/?p=324</guid>
		<description><![CDATA[Even though amazon.co.uk ship to Ireland they don&#8217;t price their products in Euro. It&#8217;s not until we reach the very last page of the order process that we see the full Euro value of the order with Irish VAT applied. What this plugin does is update each product page with the equivalent Euro price. The [...]]]></description>
			<content:encoded><![CDATA[<p>Even though amazon.co.uk ship to Ireland they don&#8217;t price their products in Euro. It&#8217;s not until we reach the very last page of the order process that we see the full Euro value of the order with Irish VAT applied.</p>
<p>What this plugin does is update each product page with the equivalent Euro price. The GBP to EUR rate is retrieved in real time from Yahoo Finance. The Irish VAT rate of 21% is included except on books which are exempt from VAT.</p>
<p>Now <a href="https://chrome.google.com/extensions/detail/ljbghemliajpgabhbaecbipkgngkoalf?hl=en">available on Chrome</a>. </p>
<p>The original Firefox version is still available <a href="http://userscripts.org/scripts/show/64262">here</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.17od.com/2010/07/01/amazon-prices-for-ireland-chrome-extension/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.17od.com/2010/07/01/amazon-prices-for-ireland-chrome-extension/</feedburner:origLink></item>
		<item>
		<title>UPM 1.6 Released</title>
		<link>http://feedproxy.google.com/~r/AdrianSmithsBlog/~3/aUlagZNbLwU/</link>
		<comments>http://www.17od.com/2010/06/23/upm-1-6-released/#comments</comments>
		<pubDate>Wed, 23 Jun 2010 11:45:06 +0000</pubDate>
		<dc:creator>Adrian</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[upm]]></category>

		<guid isPermaLink="false">http://www.17od.com/?p=320</guid>
		<description><![CDATA[Universal Password Manager 1.6 has just been released. It can be downloaded here. From the release notes&#8230; Added the ability to export/import from/to a CSV file Added a random password generator Removed the dependency on JCE Unlimited Strength Jurisdiction Policy Files Added support for using HTTPS URLs with database sharing Set focus on the password [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://upm.sourceforge.net">Universal Password Manager</a> 1.6 has just been released. It can be downloaded <a href="http://sourceforge.net/projects/upm/">here</a>.</p>
<p>From the release notes&#8230;</p>
<ul>
<li>Added the ability to export/import from/to a CSV file</li>
<li>Added a random password generator</li>
<li>Removed the dependency on JCE Unlimited Strength Jurisdiction Policy Files</li>
<li>Added support for using HTTPS URLs with database sharing</li>
<li>Set focus on the password field on all enter master password dialogs</li>
<li>Added Spanish translation (courtesy of Victor Alfonso Pineda)</li>
<li>Resize the &#8220;Notes&#8221; text area when the Account Details dialog is resized</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.17od.com/2010/06/23/upm-1-6-released/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://www.17od.com/2010/06/23/upm-1-6-released/</feedburner:origLink></item>
		<item>
		<title>UPM 1.1 Released</title>
		<link>http://feedproxy.google.com/~r/AdrianSmithsBlog/~3/BPMyVLrXyeU/</link>
		<comments>http://www.17od.com/2010/03/30/upm-1-1-released/#comments</comments>
		<pubDate>Tue, 30 Mar 2010 18:55:10 +0000</pubDate>
		<dc:creator>Adrian</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[android]]></category>
		<category><![CDATA[upm]]></category>

		<guid isPermaLink="false">http://www.17od.com/?p=305</guid>
		<description><![CDATA[With this release UPM on Android reaches feature parity with the desktop version. The main features included with this release are, Shared Database support Delete Database support Lots of bugs fixes and improvements The shared database feature was the primary focus of 1.1. With this it&#8217;s now possible to sync your password database with the [...]]]></description>
			<content:encoded><![CDATA[<p>With this release <a href="http://upm.sourceforge.net/">UPM on Android</a> reaches feature parity with the desktop version. The main features included with this release are,</p>
<ul>
<li>Shared Database support</li>
<li>Delete Database support</li>
<li>Lots of bugs fixes and improvements</li>
</ul>
<p>The shared database feature was the primary focus of 1.1. With this it&#8217;s now possible to sync your password database with the desktop version. For full details on how to setup and use database sharing see the <a href="http://upm.sourceforge.net/userguide.html">user guide</a>. </p>
<p>You can upgrade from the Android Marketplace or <a href="https://sourceforge.net/projects/upm/files/UPM/upm-android-1.1/UPM-Android-1.1.apk/download">download the APK</a> directly from Sourceforge.</p>
<p>If you have any problems post please use the <a href="https://sourceforge.net/projects/upm/forums/forum/517034">Help Forum</a>.</p>
<p><strong>UPDATE: When you upgrade you may get an error telling you UPM is no longer available when you try to start it. To fix this you should restart your phone and recreate any shortcut you have to UPM on your Home screen.</strong></p>
<p><strong>For those who are interested this seems to be a problem with Android 1.5 and how it handles a change to the main Activity after an upgrade. If you have any experience or details on this problem I&#8217;d be interested hear about it.</strong></p>
]]></content:encoded>
			<wfw:commentRss>http://www.17od.com/2010/03/30/upm-1-1-released/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://www.17od.com/2010/03/30/upm-1-1-released/</feedburner:origLink></item>
		<item>
		<title>Bookmarks for 2010-03-05</title>
		<link>http://feedproxy.google.com/~r/AdrianSmithsBlog/~3/I9bwE786iJY/</link>
		<comments>http://www.17od.com/2010/03/04/bookmarks-for-2010-03-05/#comments</comments>
		<pubDate>Thu, 04 Mar 2010 20:03:29 +0000</pubDate>
		<dc:creator>Adrian</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[bookmarks]]></category>

		<guid isPermaLink="false">http://www.17od.com/?p=296</guid>
		<description><![CDATA[Randy Pausch: Really achieving your childhood dreams &#124; Video on TED.com Randy Pausch shares his story. Amazing stuff. I can only imagine what it would have been like to work (or play) with this man. Oracle DBMS_CHANGE_NOTIFICATION An interesting way of subscribing to events in an Oracle db. Could be used as an alternative to [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.ted.com/talks/randy_pausch_really_achieving_your_childhood_dreams.html">Randy Pausch: Really achieving your childhood dreams | Video on TED.com</a><br />
Randy Pausch shares his story. Amazing stuff. I can only imagine what it would have been like to work (or play) with this man.</p>
<p><a href="http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14258/d_chngnt.htm">Oracle DBMS_CHANGE_NOTIFICATION</a><br />
An interesting way of subscribing to events in an Oracle db. Could be used as an alternative to triggers where the work to be carried out is not possible from a trigger or needs to be done async to the trigger.</p>
<p><a href="http://quicksharp.sourceforge.net/">QuickSharp</a><br />
<a href="http://monodevelop.com/">MonoDevelop</a><br />
<a href="http://sharpdevelop.com/">SharpDevelop IDE for C#</a><br />
A few opensource C# IDEs.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.17od.com/2010/03/04/bookmarks-for-2010-03-05/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.17od.com/2010/03/04/bookmarks-for-2010-03-05/</feedburner:origLink></item>
		<item>
		<title>Multipart form upload on Android</title>
		<link>http://feedproxy.google.com/~r/AdrianSmithsBlog/~3/SwNi66sfhWE/</link>
		<comments>http://www.17od.com/2010/02/18/multipart-form-upload-on-android/#comments</comments>
		<pubDate>Thu, 18 Feb 2010 19:49:55 +0000</pubDate>
		<dc:creator>Adrian</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[android]]></category>
		<category><![CDATA[java]]></category>

		<guid isPermaLink="false">http://www.17od.com/?p=280</guid>
		<description><![CDATA[Android 1.5 includes Apache HttpClient 4 for the purposes of making HTTP requests. Unfortunately HttpClient 4 (or the version included with Android anyway) doesn&#8217;t appear to support multipart form uploads. As it happens writing a solution from scratch (at the HTTP layer that is) is pretty straight forward. The main challenge is understanding how the [...]]]></description>
			<content:encoded><![CDATA[<p>Android 1.5 includes <a href="http://hc.apache.org/httpcomponents-client/index.html">Apache HttpClient 4</a> for the purposes of making HTTP requests. Unfortunately HttpClient 4 (or the version included with Android anyway) doesn&#8217;t appear to support multipart form uploads.</p>
<p>As it happens writing a solution from scratch (at the HTTP layer that is) is pretty straight forward. The main challenge is understanding how the POST request should be structured. Once you know that it&#8217;s simply a matter of putting all the pieces together.</p>
<p>The connection is managed using the <strong>java.net.HttpURLConnection</strong> class. There&#8217;s a few properties that need to set on the connection to ensure it can be written to and read from,</p>
<pre name="code" class="java:nocontrols">
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setUseCaches(false);
</pre>
<p>A special header informs the server that this will be a multipart form submission.</p>
<pre name="code" class="java:nocontrols">
conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=xxxxxxxxxx");
</pre>
<p>The &#8220;boundry&#8221; can be any string. In this example it&#8217;s &#8220;xxxxxxxxxx&#8221;. It&#8217;s used in the body of the request to seperate each field being submitted.</p>
<p>Next comes the main body of the request. Each field being submitted follows the same pattern. For example, to submit a text file called &#8220;helloworld.txt&#8221; with the contents &#8220;Hello World&#8221; and using the boundry string &#8220;xxxxxxxxxx&#8221; here&#8217;s what the request would look like,</p>
<pre>
--xxxxxxxxxx
Content-Disposition: form-data; name="filetoupload"; filename="helloworld.txt"
Content-Type: text/plain

Hello World
--xxxxxxxxxx--
</pre>
<p>The final <code>--</code> is important. It tells the server it&#8217;s the end of the submission.</p>
<p>Here&#8217;s a full method that&#8217;s used to upload a file to a URL. It can optionally take a username and password which is used to perform BASIC authentication.</p>
<pre name="code" class="java:collapse">
    public static void put(String targetURL, File file, String username, String password) throws Exception {

        String BOUNDRY = "==================================";
        HttpURLConnection conn = null; 

        try {

            // These strings are sent in the request body. They provide information about the file being uploaded
            String contentDisposition = "Content-Disposition: form-data; name=\"userfile\"; filename=\"" + file.getName() + "\"";
            String contentType = "Content-Type: application/octet-stream";

            // This is the standard format for a multipart request
            StringBuffer requestBody = new StringBuffer();
            requestBody.append("--");
            requestBody.append(BOUNDRY);
            requestBody.append('\n');
            requestBody.append(contentDisposition);
            requestBody.append('\n');
            requestBody.append(contentType);
            requestBody.append('\n');
            requestBody.append('\n');
            requestBody.append(new String(Util.getBytesFromFile(file)));
            requestBody.append("--");
            requestBody.append(BOUNDRY);
            requestBody.append("--");

            // Make a connect to the server
            URL url = new URL(targetURL);
            conn = (HttpURLConnection) url.openConnection();

            // Put the authentication details in the request
            if (username != null) {
                String usernamePassword = username + ":" + password;
                String encodedUsernamePassword = Base64.encodeBytes(usernamePassword.getBytes());
                conn.setRequestProperty ("Authorization", "Basic " + encodedUsernamePassword);
            }

            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDRY);

            // Send the body
            DataOutputStream dataOS = new DataOutputStream(conn.getOutputStream());
            dataOS.writeBytes(requestBody.toString());
            dataOS.flush();
            dataOS.close();

            // Ensure we got the HTTP 200 response code
            int responseCode = conn.getResponseCode();
            if (responseCode != 200) {
                throw new Exception(String.format("Received the response code %d from the URL %s", responseCode, url));
            }

            // Read the response
            InputStream is = conn.getInputStream();
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            byte[] bytes = new byte[1024];
            int bytesRead;
            while((bytesRead = is.read(bytes)) != -1) {
                baos.write(bytes, 0, bytesRead);
            }
            byte[] bytesReceived = baos.toByteArray();
            baos.close();

            is.close();
            String response = new String(bytesReceived);
            
            // TODO: Do something here to handle the 'response' string

        } finally {
            if (conn != null) {
                conn.disconnect();
            }
        }

    }
</pre>
<p>There&#8217;s nothing in this code particular to Android so it will work in any java application.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.17od.com/2010/02/18/multipart-form-upload-on-android/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://www.17od.com/2010/02/18/multipart-form-upload-on-android/</feedburner:origLink></item>
		<item>
		<title>Bookmarks for 2010-02-14</title>
		<link>http://feedproxy.google.com/~r/AdrianSmithsBlog/~3/dEaMR95Lqcg/</link>
		<comments>http://www.17od.com/2010/02/14/bookmarks-for-2010-02-14/#comments</comments>
		<pubDate>Sun, 14 Feb 2010 20:33:31 +0000</pubDate>
		<dc:creator>Adrian</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[bookmarks]]></category>

		<guid isPermaLink="false">http://www.17od.com/?p=272</guid>
		<description><![CDATA[The Pleasures of Counting by T. W. K&#246;rner An interesting looking maths book. One to add to the &#8220;must read&#8221; list. The Four Steps to the Epiphany by Steven Gary Blank &#34;Step-by-step strategy of how to successfully organize sales, marketing and business development for a new product or company.&#34; Steak: How to Turn Cheap &#8220;Choice&#8221; [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.amazon.co.uk/gp/product/0521568234">The Pleasures of Counting by T. W. K&ouml;rner</a><br />
An interesting looking maths book. One to add to the &#8220;must read&#8221; list.</p>
<p><a href="http://www.amazon.com/Four-Steps-Epiphany-Steven-Blank/dp/0976470705">The Four Steps to the Epiphany by Steven Gary Blank</a><br />
&quot;Step-by-step strategy of how to successfully organize sales, marketing and business development for a new product or company.&quot;</p>
<p><a href="http://steamykitchen.com/163-how-to-turn-cheap-choice-steaks-into-gucci-prime-steaks.html">Steak: How to Turn Cheap &ldquo;Choice&rdquo; Steak into Gucci &ldquo;Prime&rdquo; Steak</a><br />
How to cook a really tasty steak using a *lot* of salt. I&#039;ll definitely be trying this one out.</p>
<p><a href="http://www.cykod.com/blog/post/2010-01-design-0101-for-programmers">Design 0.101 for Programmers</a><br />
A nice step by step guide describing how to build a simple but nicely styled set of web pages. I usually use YUI or Blueprint to give me the basics but sometimes they can be a bit heavy if all you want is a simple page or two.</p>
<p><a href="http://www.fiddler2.com/fiddler2/">Fiddler Web Debugger</a><br />
Useful proxy based tool for inspecting and &quot;fiddling&quot; with HTTP requests and responses.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.17od.com/2010/02/14/bookmarks-for-2010-02-14/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.17od.com/2010/02/14/bookmarks-for-2010-02-14/</feedburner:origLink></item>
		<item>
		<title>Identifying Performance Issues on Android</title>
		<link>http://feedproxy.google.com/~r/AdrianSmithsBlog/~3/dgi4qt2ylqo/</link>
		<comments>http://www.17od.com/2010/02/09/identifying-performance-issues-on-android/#comments</comments>
		<pubDate>Tue, 09 Feb 2010 20:06:37 +0000</pubDate>
		<dc:creator>Adrian</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[android]]></category>

		<guid isPermaLink="false">http://www.17od.com/?p=256</guid>
		<description><![CDATA[While application performance is always in the back of your mind when developing PC applications it becomes much more important when developing on a mobile platform. The hardware is slower and the user expectations are much higher. This problem came to the fore for me recently as I was porting UPM to the Android platform. [...]]]></description>
			<content:encoded><![CDATA[<p>While application performance is always in the back of your mind when developing PC applications it becomes much more important when developing on a mobile platform. The hardware is slower and the user expectations are much higher.</p>
<p>This problem came to the fore for me recently as I was porting <a href="http://upm.sourceforge.net/">UPM</a> to the Android platform. Since UPM is a Java application I was able to reuse quite a bit of the code with little or no modification (all bar the SWING code actually).</p>
<p>During the porting process I found that opening the password database on the Android Emulator took about 12 seconds. This was a sub-second operation on the PC version so there was obviously a problem. Using <a href="http://developer.android.com/guide/developing/tools/traceview.html">Traceview</a>, the profiling tool that comes with the <a href="http://developer.android.com/sdk/index.html">Android SDK</a>, the problem soon became apparent.</p>
<p>UPM stores all it&#8217;s data in an encrypted file. This file is read into memory where it&#8217;s decrypted. Here&#8217;s the code that was reading in the file&#8230;</p>
<pre name="code" class="java">
    FileInputStream fis = new FileInputStream(databaseFile);
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    int i = 0;
    while ((i = fis.read()) != -1) {
        baos.write(i);
    }
    byte[] fullDatabase = baos.toByteArray();
    baos.close();
    fis.close();
</pre>
<p>Looking at it now it&#8217;s obviously bad code from a performance point of view as it&#8217;s reading in the file byte by byte. The reason I never replaced it was that it simply wasn&#8217;t a problem when running on a PC. The database file it reads is only a few kilobytes in size so it ran in under a second. </p>
<p>After identifying the bad code I replaced it with the following which runs in under a second.</p>
<pre name="code" class="java">
        InputStream is = new FileInputStream(file);
    
        // Get the size of the file
        long length = file.length();
    
        // Create the byte array to hold the data
        byte[] bytes = new byte[(int)length];
    
        // Read in the bytes
        int offset = 0;
        int numRead = 0;
        while (offset &lt; bytes.length
               &amp;&amp; (numRead=is.read(bytes, offset, bytes.length-offset)) &gt;= 0) {
            offset += numRead;
        }
    
        // Ensure all the bytes have been read in
        if (offset &lt; bytes.length) {
            throw new IOException("Could not completely read file " + file.getName());
        }
    
        is.close();
</pre>
<p>The lesson here is that Android, and mobile platforms in general, require you think a little bit more about elements of your design and code than you might normally.</p>
<p>Some useful Android links:<br />
<a href="http://developer.android.com/guide/practices/design/performance.html">Designing for Performance</a><br />
<a href="http://developer.android.com/guide/practices/design/responsiveness.html">Designing for Responsiveness</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.17od.com/2010/02/09/identifying-performance-issues-on-android/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.17od.com/2010/02/09/identifying-performance-issues-on-android/</feedburner:origLink></item>
		<item>
		<title>Bookmarks for 2010-02-09</title>
		<link>http://feedproxy.google.com/~r/AdrianSmithsBlog/~3/z5Q2C7aiYwc/</link>
		<comments>http://www.17od.com/2010/02/09/bookmarks-for-2010-02-09/#comments</comments>
		<pubDate>Tue, 09 Feb 2010 13:27:29 +0000</pubDate>
		<dc:creator>Adrian</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[bookmarks]]></category>

		<guid isPermaLink="false">http://www.17od.com/?p=246</guid>
		<description><![CDATA[Intel X25-M Mainstream Solid State Drive &#8211; 34nm This SSD has been getting great reviews. A bit expensive but I think the performance gain would be worth it, especially on a laptop. Patchbin &#8211; Share and collaborate on patches An open source code review / code sharing app. Looks nice and simple. It&#8217;s written in [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.amazon.co.uk/Intel-X25-M-Mainstream-Solid-State/dp/B002MWCEAI">Intel X25-M Mainstream Solid State Drive &#8211; 34nm</a><br />
This SSD has been getting great reviews. A bit expensive but I think the performance gain would be worth it, especially on a laptop.</p>
<p><a href="http://patchbin.com/haLJ28">Patchbin &#8211; Share and collaborate on patches</a><br />
An open source code review / code sharing app. Looks nice and simple. It&#8217;s written in Python and runs on Django.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.17od.com/2010/02/09/bookmarks-for-2010-02-09/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://www.17od.com/2010/02/09/bookmarks-for-2010-02-09/</feedburner:origLink></item>
	</channel>
</rss>
