01 July 2013

Amazon AWS - Signature Version 4


If you decide to try and interact with AWS Glacier API or certain other AWS services you will need to interact with their signature version 4 authentication. Unfortunately in ColdFusion this is one of the hardest things I've ever had to do. Not really ColdFusion's fault, and not really Amazon's fault. Their documentation is comprehensive (although a little confusing) it is just incredibly fiddly. Hashing is a process where a single wrong character completely changes everything. So one slip up causes failures and it can be difficult to determine what you've done wrong.

I have previously blogged about AWS Signiature Version 2 and using it with AWS SES. This article also touches on HMAC and a few of the other key concepts:
http://webdeveloperpadawan.blogspot.co.uk/2012/02/coldfusion-and-amazon-aws-ses-simple.html


AWS Glacier - http://aws.amazon.com/glacier/

AWS Glacier is a very low cost storage solution designed for archiving and backing up data. The basic idea is its cheaper than S3 storage but access is limited. So you don't necessarily have immediate access to your backups. Instead access can be requested and files retrieved within a given time period.
In order to keep costs low, Amazon Glacier is optimized for data that is infrequently accessed and for which retrieval times of several hours are suitable.
- AWS Website
In order to make an API request to Glacier you are required to authenticate each request using their V4 Signature process. Data in Glacier is stored in "Vaults", similar to an S3 bucket a vault is a storage container. For the purposes of this demo I've created a vault using the AWS web management interface. I will be using the API to list all available vaults. In time I hope to expand tutorials and code to cover more complex operations. However, once you've got the signature sorted that shouldn't be too hard.

Code Glorious Code

Again I just want to make the point that I'm just addressing the signature here. I hope to expand the CFC to better deal with making full requests. That will come in time though.

Setup
This should be fairly self explanatory. 
variables.dteNow                  = DateAdd("s", GetTimeZoneInfo().UTCTotalOffset, now());
variables.strPublicKey            = "publickey";
variables.strPrivateKey           = "secretkey";

variables.oAwsSig4                = createObject("component","lib.awsSig4").init(strSecretKey = variables.strPrivateKey);

//We need a few custom date formats
variables.strCanonicalDate        = variables.oAwsSig4.getCanonicalDateFormat(dteNow = variables.dteNow);
variables.strShortDate            = variables.oAwsSig4.getShortDateFormat(dteNow = variables.dteNow);


Step 1 - Create A Canonical Request

The canonical request is basically a standard way to describe the request you are making to AWS. Be that a GET, POST to Glacier or whatever.


This is the aws documentation pseudocode that describes what's happening:

CanonicalRequest =
  HTTPRequestMethod + '\n' +
  CanonicalURI + '\n' +
  CanonicalQueryString + '\n' +
  CanonicalHeaders + '\n' +
  SignedHeaders + '\n' +
  HexEncode(Hash(Payload))

Although I think that's slightly wrong. In my example1 (below), the second empty line is unexplained.

Here's the call I make to the method:

//step 1, create canonical request
strCanonical    = variables.oAwsSig4.createCanonical(
    strHTTPRequestMethod       = "GET",
    strCanonicalURI            = "/-/vaults",
    strCanonicalQueryString    = "",
    arrCanonicalHeaders        = ["date:#variables.strCanonicalDate#","host:glacier.us-east-1.amazonaws.com","x-amz-glacier-version:2012-06-01"],
    arrSignedHeaders           = ["date","host","x-amz-glacier-version"],
    strPayLoad                 = ""
);

You'll note the payload is empty, so the hash at the bottom is simply a SHA-256 hash of "".

The finished Canonical request should look like this.
Example1:
GET
/-/vaults

date:2013-06-26T13:07:03
host:glacier.us-east-1.amazonaws.com
x-amz-glacier-version:2012-06-01

date;host;x-amz-glacier-version
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

Step 2 - Create A String To Sign

The string to sign is a little harder to explain out of context. It's basically the message we will hash which will authorize the request to AWS. It's a short and simple string with a very concise format.

The pseudocode is fine here and describes it quite well:
StringToSign  =
Algorithm + '\n' +
RequestDate + '\n' +
CredentialScope + '\n' +
HexEncode(Hash(CanonicalRequest))

Here's my function call:
//Step 2 - Create String To Sign    
strStringToSign    = variables.oAwsSig4.createStringToSign(
    strAlgorithm        = "AWS4-HMAC-SHA256",
    strRequestDate        = variables.oAwsSig4.getStringToSignDateFormat(dteNow = variables.dteNow),
    strCredentialScope    = strShortDate & "/us-east-1/glacier/aws4_request",
    strCanonicalRequest    = strCanonical
);


This is the finished string to sign:
AWS4-HMAC-SHA256
20130626T133038Z
20130626/us-east-1/glacier/aws4_request
6d26f46dbf5d48665e06f44a2f9a65368b3b8d9ef45638b1496fbbe6604ed9db

Step 3a - Calculate Signing Key

OK Now it gets complicated. This is where we start running things through the HMAC function and problems quickly occur. If you do it right though, it'll all come together. AWS do this all in one step, but I think its easier as two.

Here's the documentation pseudocode:

kSecret = Your AWS Secret Access Key
kDate = HMAC("AWS4" + kSecret, Date)
kRegion = HMAC(kDate, Region)
kService = HMAC(kRegion, Service)
kSigning = HMAC(kService, "aws4_request")

Here's my function call:
//create singing key
bSigningKey    = variables.oAwsSig4.createSigningKey(
    dateStamp    = strShortDate,
    regionName    = "us-east-1",
    serviceName    = "glacier"
);

and here's the function:
<cffunction name="createSigningKey" access="public" returnType="binary" output="false" hint="THIS WORKS DO NOT FUCK WITH IT.">
    <cfargument name="dateStamp"    type="string"    required="true" />
    <cfargument name="regionName"    type="string"    required="true" />
    <cfargument name="serviceName"    type="string"    required="true" />
    <cfscript>
        var kSecret     = JavaCast("string","AWS4" & variables.strSecretKey).getBytes("UTF8");
        var kDate       = HMAC_SHA256_bin(arguments.dateStamp, kSecret);
        var kRegion     = HMAC_SHA256_bin(arguments.regionName, kDate);
        var kService    = HMAC_SHA256_bin(arguments.serviceName, kRegion);
        var kSigning    = HMAC_SHA256_bin("aws4_request", kService);
        
        return kSigning;
    </cfscript>
</cffunction>

I know I've not included the function in the other steps, but I want to highlight the importance of two things:
  • kSecret is "AWS4" + Secret Key, then cast into bytes. This is a very important step and where I was going wrong for quite a while.
  • variables.strSecretKey is the secret key you get from AWS in your account section. It's obviously secret and shouldn't be disclosed to anyone. In my example it's set in the variables scope of the cfc.
  • The function I use HMAC_SHA256_bin accepts a binary argument as param1. This is different from the example in my previous blog post on signature version 2, which used two strings as arguments.
So you can see with four HMAC steps, the tiniest mistake means a totally different response. Obviously AWS will be doing the same thing on their end, so if the two don't match, your request won't get approved.

Step 3b - Sign it!

OK Now we bring it all together

signature = HexEncode(HMAC(derived-signing-key, string-to-sign))

We take the signing key from step 3a and the string to sign from step 2:

bSignature    = variables.oAwsSig4.HMAC_SHA256_bin(strStringToSign, bSigningKey);

Step 4 - Put it all together

Now we make our request:
<cfhttp method="GET" url="http://glacier.us-east-1.amazonaws.com/-/vaults">
    <cfhttpparam type="header"         name="Date" value="#variables.strCanonicalDate#">
    <cfhttpparam type="header"        name="x-amz-glacier-version" value="2012-06-01" />
    <cfhttpparam type="header"        name="Authorization" value="AWS4-HMAC-SHA256 Credential=#variables.strPublicKey#/#variables.strShortDate#/us-east-1/glacier/aws4_request,SignedHeaders=date;host;x-amz-glacier-version,Signature=#lcase(binaryEncode(bSignature, 'hex'))#" />
</cfhttp>

  • Note we didn't hex encode our bSigniature from before, so I do that in the value. Probably better done elsewhere, but I'll get to it.
  • Also note the public key. Again this comes from AWS management console.
  • Note the three different dates, one is the strCanonicalDate we created at the top, the other is the short date and finally the hard coded glacier version date.
That's it. That should work!  Obviously you need the cfc. Take a look below for that.


Advice

My advice to anyone attempting to do this in ColdFusion or any other language is as such:
  1. Baby Steps - The documentation is presented in steps. Get each step working perfectly before moving onto the next. They all rely on each other, so a mistake early on will just cascade and waste time later.
  2. Unit Tests - I'm a huge fan of unit tests anyway, but in this case they really helped. Setting up some great unit tests using AWS examples will help you define your input and your output and tweak your code until you get the response you're looking for.
  3. Check Responses - If you actually make a request to AWS they will tell you in the response what the problem is. Plus they'll tell you the expected canonical request and the expected string to sign. These can really help iron out any tiny discrepancies
  4. Try it in Java -  CFML Doesn't have a native HMAC function (pre CF10), and converting too and from byte arrays caused endless problems. So I just did a few piecemeal functions in Java and learned from that.

The CFC

Ah of course one final step. The cfc. As I've said I hope to improve it a great deal and perhaps open source it and put it on cflib. I've also got a bunch of unit tests I wrote which may help people improve it.
Right now I'm just pleased to have got it working and don't want to forget it all so it's going on the blog.


Thanks

I ended up not using the code, but some of Ben Nadel's stuff was really useful to understand. He's written a great cfc that I urge anyone using HMAC in CFML to consider:
http://www.bennadel.com/blog/2412-Crypto-cfc-For-Hmac-SHA1-Hmac-Sha256-and-Hmac-MD5-Code-Generation-In-ColdFusion.htm




<cfcomponent output="false">

<!---
<OWNER> = James Solo
<YEAR> = 2013

In the original BSD license, both occurrences of the phrase "COPYRIGHT HOLDERS AND CONTRIBUTORS" in the disclaimer read "REGENTS AND CONTRIBUTORS".

Here is the license template:

Copyright (c) 2013, James Solo
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

--->

    <cffunction name="init" access="public" returnType="awsSig4" output="false">
        <cfargument name="strSecretKey" type="string" required="true" />

        <cfset variables.strSecretKey        = arguments.strSecretKey />
        <cfset variables.strPublicKey        = "mypublickey" />
        <cfreturn this>
    </cffunction>


    <cffunction name="createCanonical" access="public" returnType="string" output="false" hint="Create the canonical request">
        <cfargument name="strHTTPRequestMethod"        type="string"    required="true"                 />
        <cfargument name="strCanonicalURI"            type="string"    required="true"                 />
        <cfargument name="strCanonicalQueryString"    type="string"    required="false"    default=""    />
        <cfargument name="arrCanonicalHeaders"         type="array"    required="true"                    />
        <cfargument name="arrSignedHeaders"            type="array"    required="true"                    />
        <cfargument name="strPayload"                type="string"    required="false"    default=""    />
        
        <cfscript>
            var intCount            = 0;
            var strHeaderString        = "";
            var strCanonicalRequest = 
                arguments.strHTTPRequestMethod        & chr(010) &
                arguments.strCanonicalURI            & chr(010) &
                arguments.strCanonicalQueryString    & chr(010);
            
            //Headers
            for(intCount=1; intCount <= arraylen(arrCanonicalHeaders); intCount++){
                strCanonicalRequest    &= arguments.arrCanonicalHeaders[intCount] & chr(010);
            }
            
            strCanonicalRequest    &= chr(010);
            
            //Signed headers
            for(intCount=1; intCount <= arraylen(arrSignedHeaders); intCount++){
                strHeaderString        = arguments.arrSignedHeaders[intCount];
                strCanonicalRequest    &= strHeaderString;
                
                //put a semi-colon between headers, or a new line at end
                if(intCount EQ arraylen(arrSignedHeaders)){
                    strCanonicalRequest    &= chr(010);
                }else{
                    strCanonicalRequest    &= ";";
                }
            }
            
            strCanonicalRequest    &= lcase(hash(arguments.strPayload, "SHA-256"));
            
            return trim(strCanonicalRequest);
        </cfscript>
    </cffunction>


    <cffunction name="createStringToSign" access="public" returnType="string" output="false" hint="I create the string to sign">
        <cfargument name="strAlgorithm"            type="string" required="true" />
        <cfargument name="strRequestDate"        type="string" required="true" />
        <cfargument name="strCredentialScope"    type="string" required="true" />
        <cfargument name="strCanonicalRequest"    type="string" required="true" />
        
        <cfscript>
            var strStringToSign  =
                    arguments.strAlgorithm            & chr(010) &
                    arguments.strRequestDate        & chr(010) &
                    arguments.strCredentialScope    & chr(010) &
                    lcase(hash(arguments.strCanonicalRequest, "SHA-256"));
            
            return strStringToSign;
        </cfscript>
    </cffunction>


    <cffunction name="createSigningKey" access="public" returnType="binary" output="false" hint="THIS WORKS DO NOT FUCK WITH IT.">
        <cfargument name="dateStamp"    type="string"    required="true" />
        <cfargument name="regionName"    type="string"    required="true" />
        <cfargument name="serviceName"    type="string"    required="true" />
        <cfscript>
            var kSecret        = JavaCast("string","AWS4" & variables.strSecretKey).getBytes("UTF8");
            var kDate        = HMAC_SHA256_bin(arguments.dateStamp, kSecret);
            var kRegion        = HMAC_SHA256_bin(arguments.regionName, kDate);
            var kService    = HMAC_SHA256_bin(arguments.serviceName, kRegion);
            var kSigning    = HMAC_SHA256_bin("aws4_request", kService);
            
            return kSigning;
        </cfscript>
    </cffunction>


    <cffunction name="HMAC_SHA256_bin" access="public" returntype="binary" output="false" hint="THIS WORKS DO NOT FUCK WITH IT."> 
        <cfargument name="signMessage"    type="string" required="true" />
        <cfargument name="signKey"        type="binary" required="true" /> 
        
        <cfset var jMsg = JavaCast("string",arguments.signMessage).getBytes("UTF8") /> 
        <cfset var jKey = arguments.signKey />
        
        <cfset var key = createObject("java","javax.crypto.spec.SecretKeySpec") /> 
        <cfset var mac = createObject("java","javax.crypto.Mac") /> 
        
        <cfset key = key.init(jKey,"HmacSHA256") /> 
        
        <cfset mac = mac.getInstance(key.getAlgorithm()) /> 
        <cfset mac.init(key) /> 
        <cfset mac.update(jMsg) /> 
        
        <cfreturn mac.doFinal() />
    </cffunction>


    <cffunction name="toHex" access="public" returnType="string" output="false" hint="I convert binary to hex">
        <cfargument name="bSignature"        type="binary" required="true" /> 
        <cfreturn lcase(binaryEncode(arguments.bSignature, "hex")) />
    </cffunction>
    

    <cffunction name="getCanonicalDateFormat" access="public" returnType="string" output="false" hint="I return a formatted date time for the canonical part of the process">
        <cfargument name="dteNow"    type="date"    required="true" />
        
        <cfreturn "#dateformat(arguments.dteNow, 'yyyy-mm-dd')#T#TimeFormat(arguments.dteNow, 'HH:mm:ss')#" />
    </cffunction>
    

    <cffunction name="getStringToSignDateFormat" access="public" returnType="string" output="false" hint="I return a formatted date time for the string to sign section">
        <cfargument name="dteNow"    type="date"    required="true" />
        
        <cfreturn "#dateformat(arguments.dteNow, 'yyyymmdd')#T#TimeFormat(arguments.dteNow, 'HHmmss')#Z" />
    </cffunction>
    

    <cffunction name="getShortDateFormat" access="public" returnType="string" output="false" hint="I return a short date time">
        <cfargument name="dteNow"    type="date"    required="true" />
        
        <cfreturn "#dateformat(arguments.dteNow, 'yyyymmdd')#" />
    </cffunction>


</cfcomponent>

10 June 2013

CFML REST webservices with Railo

I've been doing a lot of REST web services with CFML and Railo lately and wanted to write up my experiences in case it helps.

First you need to setup Railo with your webservice cfc:
http://www.getrailo.org/index.cfm/whats-up/railo-40-released/features/rest-services/

Second you need to create and configure your cfc:
<cfcomponent rest="true" restpath="/hello">

The restpath provides the step in your URL from which your service is accessed. A normal REST webservice is pretty straightforward. Ensure your method is set to access="remote" and add in httpMethod and a restPath param to the cffunction.
<cffunction name="getmuppets" access="remote" httpmethod="GET" restpath="/getmuppets">

The restpath identifies the url structure you'll use to access the webservice.
The httpmethod tells the webservice if it should respond to GET/POST/PUT etc methods. These methods are defined and talked about more in REST definitions: http://en.wikipedia.org/wiki/Representational_state_transfer#Vocabulary_re-use_vs._its_arbitrary_extension:_HTTP_and_SOAP

Returning data is fairly standard, but if you want to return JSON then you might want to look at my previous blog post.

I've found that unlike much of CFML REST is case sensitive, so its a good idea to make everything lowercase.

This should be enough to get you going, but pretty soon you'll need to add arguments. So lets have a quick look at REST arguments. Lets assume for now we're just interested in a GET request.

You add your cfargument as your normally would, but you also need a param called restArgSource.

<cfargument name="intage"    type="numeric"    restArgSource="Path">

Your new method would look like this:
    <cffunction name="getmuppets" access="remote" produces="application/json" httpmethod="GET" restpath="/getmuppets/intage/{intage}/strsex/{strsex}/">
        <cfargument name="intage"    type="numeric"    restArgSource="Path">
        <cfargument name="strsex"    type="string"    restArgSource="Path">
        
        .....
    </cffunction>

Pay particular attention to how the restpath needs to be updated to match the new arguments. We're using restArgSource set to path, which means your url needs to provide those arguments. Here's an example URL:
http://localhost/rest/demo/hello/getmuppets/intage/30/strsex/male
Each step in the URL is a piece of the puzzle.

There are a few types that restArgSource accepts:
  • Path
  • Query
  • Matrix
  • Cookie / Header
  •  Form
Query is pretty straightforward, instead of using path (as above) you can just get your arguments from the query scope, i.e. ?strage=30. Form is when an argument comes from the FORM scope and you'd normally only use this for post and put httpMethods.
For a full explanation of these types, this article provides a good explanation:
http://www.adobe.com/devnet/coldfusion/articles/restful-web-services.html

That's it, you should be ready to write your own. Best of luck!







30 May 2013

Railo Rest JSON Web Service


So I've been writing lots of REST web services lately with Railo 4.0 and noticed a strange issue / feature when returning json.

So I write me a nice little function and I think everything will work with a little CFML magic:

    <cffunction name="getmuppets" access="remote" returntype="string" httpmethod="GET" restpath="/getmuppets">
        <cfscript>
            var arrMuppets    = [
                {name = "kermit", age = 20},
                {name = "fuzzy", age = 30},
                {name = "animal", age = 40}
            ];
            
            return serializeJson(arrMuppets)
        </cfscript>
    </cffunction>


All good? No :( The json is fine when you call the function locally, but when you call it as a rest webservice all the double quotes get escaped. Which renders it invalid json and is not much use for anything.
"[{\"age\":20,\"name\":\"kermit\"},{\"age\":30,\"name\":\"fuzzy\"},{\"age\":40,\"name\":\"animal\"}]"


So I eventually figured out you've got to change the headers and content returned by the function.
    <cffunction name="getmuppets" access="remote" produces="application/json" httpmethod="GET" restpath="/getmuppets">
        <cfscript>
            var arrMuppets    = [
                {name = "kermit", age = 20},
                {name = "fuzzy", age = 30},
                {name = "animal", age = 40}
            ];
            
            response    = {
                status        = 200,
                headers        = {},
                content        = serializeJson(arrMuppets)
            };
        
            restSetResponse(response);
        </cfscript>
    </cffunction>

Once you do all that, you get valid json:


[{"age":20,"name":"kermit"},{"age":30,"name":"fuzzy"},{"age":40,"name":"animal"}]

18 May 2013

Node JS

For no particular reason I thought I'd have a stab at Node.js today. I'm a bit curious and keen to see what all the fuss is about. Much (I suspect) like a lot of web devs out there I'm good at JS and jQuery (I even dabbled in prototype and YUI) but would've call myself a JavaScript pro! Today I just wanted to get a Hello World out the door and then later try and find out a bit more and perhaps get more advanced.

Install
So I must have read a dozen different tutorials today and every one of them is different. The official note.js site has an instillation guide https://github.com/joyent/node/wiki/Installation but I found it a bit daunting, so I pieced a few together.

I'm on Ubuntu so I downloaded the node-v0.10.7.tar.gz file from http://nodejs.org/ and unpacked it to a new directory.

Then I opened up a console and simply typed:

sudo make install

This took a while as Ubuntu busied itself, but that was it, pretty simple.
You can verify everything is running by typing

node --version

Get Started

Then I created a directory under /var/www/ and the obligatory Hello World file:

console.log("Hello World - All your base belong to me");

Then, still in the console I moved to my new application directory and executed my file:

node helloworld.js

That was it! Easy as pie so far!

14 May 2013

Android Fragments

In Android a fragment is a "behaviour or a portion of user interface in an Activity". I first met fragments when putting maps in my Android activity. They're also useful for putting various UI components on one activity.
I've adapted this example from here http://developer.android.com/training/basics/fragments/index.html
Here's the simple breakdown of using a list fragment:

1) Create an activity_main.xml in res/layout/ as such:
<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <fragment android:name="com.example.droidtestnew.smallpage"
              android:id="@+id/article_fragment"
              android:layout_weight="2"
              android:layout_width="0dp"
              android:layout_height="match_parent" />

</LinearLayout>
2) Create another activity_main.xml in res/layout-large/ (note the second fragment):
<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <fragment android:name="com.example.droidtestnew.smallpage"
              android:id="@+id/headlines_fragment"
              android:layout_weight="1"
              android:layout_width="0dp"
              android:layout_height="match_parent" />

    <fragment android:name="com.example.droidtestnew.smallpage"
              android:id="@+id/article_fragment"
              android:layout_weight="2"
              android:layout_width="0dp"
              android:layout_height="match_parent" />

</LinearLayout>
3) Create a java class called smallpage.java
package com.example.droidtestnew;

import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.widget.ArrayAdapter;

public class smallpage extends ListFragment {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        String arrHello[] = {
            "Hello One",
            "Goodbye Two"
        };
        
        // We need to use a different list item layout for devices older than Honeycomb
        int layout = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ?
                android.R.layout.simple_list_item_activated_1 : android.R.layout.simple_list_item_1;

        // Create an array adapter for the list view, using the Ipsum headlines array
        setListAdapter(new ArrayAdapter<String>(getActivity(), layout, arrHello));
    }

}
4) Change MainActivity.java to extend FragmentActivity:
public class MainActivity extends FragmentActivity {
You're done. That should be all you need. If you launch this on a small screen, you'll see the one fragment list, if you launch it on a tablet, you'll see two lists.

Easy as pie! Obviously this is an incredibly basic example, but it should get you started with fragments.

28 April 2013

Building a CF SOAP Webservice


I recently needed to create a web service which pleased me as its very easy with coldFusion.


Although, that said, one thing that has often puzzled me is the Application.cfc and the cfc initialization. You probably wouldn’t want to use your normal Application.cfc as it’s likely a bit excessive. To my mind webservice requests could take place weeks apart, or just minutes and should be lightening fast, so a very lightweight initialization process would be ideal.

Lets assume a very basic webservice.cfc:


<cfcomponent output="false">
    
    <cffunction name="getUsers" access="remote" returnType="query" output="false" hint="I get some users">
        <cfreturn application.oUsers.getUsers() />
    </cffunction>
    
</cfcomponent>

So oUsers is our DAO or Business object which we use in our application. Normally it would be passed in with an init method, but with a webservice we don’t have the same concept of init’ing objects. So how does one go about initializing our DAO? In the past I’ve seen many takes on this. I’ve seen:

In the method:
<cffunction ...>
    <cfset var oUsers = createObject(...)>
    <cfreturn var oUsers.getUsers()>

In the actual webservice.cfc, scoping it this/variables/application
<cfcomponent output="false">
    <cfset variables.oUsers = createObject(...)>
    <cffunction ...


Both of the above involve the dao cfc being re-created on every web-service request. Not exactly ideal in terms of performance.

So I think the best idea I’ve seen so far is create an application.cfc like so:


<cfcomponent output="false">
    <cfset this.strDsn            = "mydsn" />
    
    <cffunction name="onApplicationStart" access="public" returnType="boolean" output="false">
        <cfset application.oUsers    = createObject("component","usersDao").init(strDsn    = this.strDsn) />
        <cfreturn true />
    </cffunction>
    
</cfcomponent>


This gives a lightweight application scope in which we can initialize our object and then call throughout our webservices! Excellent!

If you’ve got any suggestions on how to improve this, please feel free to comment.

20 March 2013

Hamlet's Monkey - Part 3

I've previously blogged about my Hamlet's Monkey project.

Part 1 where I introduced the concept and did it in CFML:
http://webdeveloperpadawan.blogspot.co.uk/2012/10/hamlets-monkey-code-for-fun.html

Part 2 Where I ported the project into a java class with some JSON file read and writing:
http://webdeveloperpadawan.blogspot.co.uk/2013/03/hamlets-monkey-part-2.html

OK So now this whole project is moving toward where I was really excited to take it. GOOGLE! hahah I want to put this project on Google App Engine (GAE) so it uses cloud computing. That way a GAE cloud instance is like an actual monkey, tapping away at the keyboard and trying to re-write Hamlet! Awesome! This straight away introduces two potential problems:
  1. I've got to turn the project into a java servlet
  2. Tracking progress - In part 2 we added file storage, this won't work in the cloud, so we'll need to find a better method.


OK So converting the main crux of the method to a servlet isn't that complicated. The first thing you need to do is install the GAE plugin for eclipse. https://developers.google.com/appengine/docs/java/tools/eclipse Then we'll convert the project we made in Part 2 to a servlet, the public class needs to extend HTTPServlet:
public class Shakespearemonkey extends HttpServlet {

and the main method becomes doGet, which is what is called when the servlet responds to a http get request:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException {


    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException {
        int            intCount                 = 0;
        String        strSubString            = "";
        String        strShakespeare            = Shakespeare.replaceAll("[^a-zA-Z]", ""); //Shakespeare without spaces etc
        String        strMonkeyString            = "";
        String        strBestSoFar            = "";
        response.setContentType("text/html");
        
        while (intCount < intNumLoops) {
            intCount++;
            
            //generate the random guess, one keystroke at a time
            strMonkeyString    = strMonkeyString + Character.toString(generateRandomLetter());
            
            strSubString    =    strShakespeare.substring(0,strMonkeyString.length());
            
            //check if we've guessed correctly so far
            if(strMonkeyString.equalsIgnoreCase(strSubString)){
                //Is this our best guess so far
                if(strSubString.length() > strBestSoFar.length()){
                    strBestSoFar    =    strSubString;
                }
            }else{
                //incorrect guess, start again
                strMonkeyString    = "";
            }
        }
        
        trackProgress(intCount,strBestSoFar);
        
        //purely for output, re-read the latest and update user on progress
        try {
            response.getWriter().println("Good Morning, I am your monkey! I will be trying to guess the string: " + strShakespeare + "<br />");
            MonkeyResults monkeyresults    = readResultsFromFile();
            response.getWriter().println("My best guess so far is: ");
            response.getWriter().println((String) monkeyresults.getBestGuess());
            response.getWriter().println("<br />I have made ");
            response.getWriter().println((int) monkeyresults.getKeyStrokes());
            response.getWriter().println("keystrokes");
        } catch (IOException e) {
            e.printStackTrace();
        }
        
    }


So what I've done is created an object for storing all our progress data. Possibly not necessary / overkill but its OO and it feels good. It's just two getters and setters, so I won't bore you with the code. What is different in the trackProgress function though is I've replaced the JSON code with this:
        MonkeyResults        monkeyResults            = readResultsFromFile();
        
        if(monkeyResults.getKeyStrokes() != 0 && monkeyResults.getBestGuess() != ""){
            strBestGuessFromFile    = (String) monkeyResults.getBestGuess();
            intKeyStrokesFromFile    = (int) monkeyResults.getKeyStrokes();
        }


So I'm going to use the GAE datastore to keep track of our progress. The first step is writing to the datastore:

    static Key            theResultsKey    = KeyFactory.createKey("Results","tblMonkeyResults");
    DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
    

    
    private void writeResultsToFile(int intKeyStrokes, String strBestGuess){
        //I write the number of keystrokes and the best guess so far to the datastore
        Entity objDaoOut = new Entity("Results", "tblMonkeyResults");
        
        objDaoOut.setProperty("intKeyStrokes",intKeyStrokes);
        objDaoOut.setProperty("strBestGuess", strBestGuess);

        datastore.put(objDaoOut);
    }
The next of course is the new read function, which returns an implementation of our local object:
    private MonkeyResults readResultsFromFile() {
        //I read results from the datastore and return an instance of class MonkeyResults
        MonkeyResults monkeyResults    = new MonkeyResults();
        long intStrokes    = 0;
        String strGuess    = "";
        
        try{
            Entity objDaoIn = datastore.get(theResultsKey);
        
            intStrokes    = (long) objDaoIn.getProperty("intKeyStrokes");
            strGuess    = (String) objDaoIn.getProperty("strBestGuess");
        }catch(EntityNotFoundException e){
            //e.printStackTrace();
        }finally{
            monkeyResults.setKeyStrokes((int)intStrokes);
            monkeyResults.setBestGuess(strGuess);
        }
        
        return monkeyResults;
    }
That's basically it. We have converted our java function to a Java Servlet and modified the file read and write to use the Google Datastore. Simples.

Once you're done, you should be able to test it locally, if it works you right click on the project and goto Google -> Deploy to App Engine. Hey presto google uploads it all for you and you should have a successfully running monkey!

Here's my monkey: http://shakespearmonkey.appspot.com/ http://pastebin.com/1etNP1ge