June 2011

Volume 26 Number 06

Forecast: Cloudy - Multi-Platform Azure Storage

By Joseph Fultz | June 2011

Joseph FultzAzure Storage is far from a device-specific technology, and that’s a good thing. This month, I’ll take a look at developing on three mobile platforms: Windows Phone 7, jQuery and Android.

To that end, I’ll create a simple application for each that will make one REST call to get an image list from a predetermined Azure Storage container and display the thumbnails in a filmstrip, with the balance of the screen displaying the selected image as seen in Figure 1.

Side-by-Side Storage Image Viewers

Figure 1 Side-by-Side Storage Image Viewers

Preparing the Storage Container

I’ll need a Azure Storage account and the primary access key for the tool I use for uploads. In the case of secure access from the client I’m developing I would also need it. That information can found in the Azure Management Portal.

I grabbed a few random images from the Internet and my computer to upload. Instead of writing upload code, I used the Azure Storage Explorer, found at azurestorageexplorer.codeplex.com. For reasons explained later, images need to be less than about 1MB. If using this code exactly, it’s best to stay at 512KB or less. I create a container named Filecabinet; once the container is created and the images uploaded, the Azure piece is ready.

Platform Paradigms

Each of the platforms brings with it certain constructs, enablers and constraints. For the Silverlight and the Android client, I took the familiar model of marshaling the data in and object collection for consumption by the UI. While jQuery has support for templates, in this case I found it easier to simply fetch the XML and generate the needed HTML via jQuery directly, making the jQuery implementation rather flat. I won’t go into detail about its flow, but for the other two examples I want to give a little more background.

Windows Phone 7 and Silverlight

If you’re familiar with Silverlight development you’ll have no problem creating a new Windows Phone 7 application project in Visual Studio 2010. If not, the things you’ll need to understand for this example are observable collections (bit.ly/18sPUF), general XAML controls (such as StackPanel and ListBox) and the WebClient. 

At the start, the application’s main page makes a REST call to Azure Storage, which is asynchronous by design. Windows Phone 7 forces this paradigm as a means to ensure that any one app will not end up blocking and locking the device. The data retrieved from the call will be placed into the data context and will be an ObservableCollection<> type.

This allows the container to be notified and pick up changes when the data in the collection is updated, without me having to explicitly execute a refresh. While Silverlight can be very complex for complex UIs, it also provides a low barrier of entry for relatively simple tasks such as this one. With built-in support for binding and service calls added to the support for touch and physics in the UI, the filmstrip to zoom view is no more difficult than writing an ASP.NET page with a data-bound Grid.

Android Activity

Android introduces its own platform paradigm. Fortunately, it isn’t something far-fetched or hard to understand. For those who are primarily .NET developers, it’s easy to map to familiar constructs, terms and technologies. In Android, pretty much anything you want to do with the user is represented as an Activity object. The Activity could be considered one of the four basic elements that may be combined to make an application: Activity, Service, Broadcast Receiver and Content Provider.

For simplicity, I’ve kept all code in Activity. In a more realistic implementation, the code to fetch and manipulate the images from Azure Storage would be implemented in a Service.

This sample is more akin to putting the database access in the code behind the form. From a Windows perspective, you might think of an Activity as a Windows Forms that has a means—in fact, the need—to save and restore state. An Activity has a lifecycle much like Windows Forms; an application could be made of one-to-many Activities, but only one will be interacting with the user at a time. For more information on the fundamentals of Android applications, go to bit.ly/d3c7C

This sample app will consist of a single Activity (bit.ly/GmWui), a BaseAdapter (bit.ly/g0J2Qx) and a custom object to hold information about the images.

Creating the UIs

The common tasks in each of the UI paradigms include making the REST call, marshaling the return to a useful datatype, binding and displaying, and handling the click event to show the zoom view of the image. First, I want to review the data coming back from the REST Get, and what’s needed for each example to get the data to something more easily consumable.

The Data

Within the application code I prefer to work with objects and not constantly have to manipulate XML, so I create an object to match the XML returned from the storage call. It looks like the code in Figure 2.

Figure 2 Object to Match XML Returned from Storage Call

<EnumerationResults ContainerName="https://jofultz.blob.core.windows.net/filecabinet">



  <Blobs>



  <Blob>



  <Name>2010-12-12+10.40.06.jpg</Name> 



  <Url>https://jofultz.blob.core.windows.net/filecabinet/2010-12-12+10.40.06.jpg</Url> 



  <LastModified>Sun, 02 Jan 2011 02:24:24 GMT</LastModified> 



  <Etag>0x8CD783B4E56116C</Etag> 



  <Size>263506</Size> 



  <ContentType>image/jpeg</ContentType> 



  <ContentEncoding /> 



  <ContentLanguage /> 



  </Blob>



  <Blob>



  <Name>cookie-monster.jpg</Name> 



  <Url>https://jofultz.blob.core.windows.net/filecabinet/cookie-monster.jpg</Url> 



  <LastModified>Mon, 27 Dec 2010 09:40:18 GMT</LastModified> 



  <Etag>0x8CD73C13542256C</Etag> 



  <Size>265995</Size> 



  <ContentType>image/jpeg</ContentType> 



  <ContentEncoding /> 



  <ContentLanguage /> 



  </Blob>



  <Blob>

I then create a representative object to hold the information I want. Mostly I’m concerned with the Name and URL fields. Figure 3 provides a look at the declaration for the objects used for each example.

Figure 3 Object Declaration for Objects Used in Each Client Example

Silverlight Android jQuery
public static ObservableCollection<StorageImage>
  ImageInfoList {get;set;}
 
...
 
public class StorageImage
{
  public string Name{get;set;}
  public string Url {get;set;}
  public BitmapImage Image {get;set;}
}
public ArrayList<BlobInfo>
  BlobList= null;
 
...
 
public class BlobInfo {
  public String Name;
  public String Url;
  public Bitmap ImageBitmap;}

None

The XML is consumed directly.

Creating the UIs

Fortunately, the way the UI is defined in Android and Silverlight is similar in their use of markup, so understanding one nearly guarantees understanding the other. Additionally, they both use an XML markup to define the UI. 

The jQuery implementation will simply use HTML and generate some elements dynamically. The big difference between the three when writing markup is knowledge of the controls/elements to be used.

Starting with the Windows Phone 7 XAML, I open up the MainPage.xaml and add a <Grid/>, which will contain a <ListBox /> for the filmstrip. The list box will contain an <ItemTemplate/> and <DataTemplate /> that will control how data will render for the filmstrip. Also in the grid will be an <Image/> control for the zoom view of the image. 

For Android, I’ll set up a similar UI construct using a LinearLayout that contains two widgets: Gallery and ImageView. For those familiar with Silverlight or Windows Presentation Foundation (WPF), a LinearLayout is like a StackPanel. Widgets are controls and this would be roughly equivalent to a StackPanel that contains two elements: a horizontal ListBox of Images and an Image control. Note that this is almost exactly what’s used in the Silverlight example. The Gallery will provide a filmstrip-style view of thumbnails and the ImageView will show a zoomed view of the selected thumbnail.

For the jQuery example, I’ll have an empty <p/> with the id assigned the name “output”; that will be where the thumbnails views will be dynamically added via the jQuery.

The Silverlight markup is a bit longer due to the handling of the binding and rendering in the markup. A little more code on the Android side handles the data loading. The markups for each are in Figure 4.

Figure 4 Markup Differences

Element Silverlight Android jQuery
Filmstrip <ListBox /> <Gallery /> <p />
Zoom View <Image /> <ImageView /> <img />

Starting Markup: Silverlight

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
  <ListBox Name="ImageList" ItemsSource="{Binding}" MaxWidth="400"
    Background="#00C23838" Margin="28,16,28,577" BorderBrush="#32D4BA29"
    ScrollViewer.HorizontalScrollBarVisibility="Auto"
    SelectionChanged="ImageList_SelectionChanged">
    <ListBox.ItemsPanel>
      <ItemsPanelTemplate>
        <StackPanel Orientation="Horizontal">
        </StackPanel>              
      </ItemsPanelTemplate>
    </ListBox.ItemsPanel>
    <ListBox.ItemTemplate>
      <DataTemplate>
        <StackPanel Orientation="Horizontal" >
          <Image Source="{Binding Image}" Height="110" Width="150"
            Name="{Binding Name}" ></Image>
        </StackPanel>
      </DataTemplate>
    </ListBox.ItemTemplate>
  </ListBox>
  <Image Height="447" HorizontalAlignment="Left" Margin="28,123,0,0"
    Name="ImageViewer" Stretch="Fill" VerticalAlignment="Top" Width="400" />
  </Grid>
</Grid>

Starting Markup: Android

<LinearLayout android:id="@+id/LinearLayout01"android:layout_width="fill_parent"
              android:layout_height="fill_parent"
              xmlns:android="https://schemas.android.com/apk/res/android"
              android:orientation="vertical">
              <Gallery xmlns:android="https://schemas.android.com/apk/res/android"
 
              android:id="@+id/Thumbnails" android:layout_width="fill_parent"
 
              android:layout_height="wrap_content" />
              <ImageView android:id="@+id/ZoomView"
 
              android:layout_width="wrap_content" android:layout_height="wrap_content"/>
</LinearLayout>

Starting Markup: jQuery

<p id="output">
 
</p>
<p>
  <img id="zoomview" height="480" width="320"  />
</p>

The Main Code

The next step is to create the code that contacts Azure Storage for information about the blobs. The fetch request takes the form of https://[your storage account].blob.core.windows.net/[your container]?comp=list; my request looks like https://jofultz.blob.core.windows.net/filecabinet?comp=list. 

Because the results are XML, in Silverlight I used LINQ to provide a nice object graph and access pattern. I wanted something like that for Java, but in the end, wanting to skip the debugging of unfamiliar technology, I chose to just work with the Document Object Model (DOM)-style interface provided by the DocumentBuilder API. Because this was a Read-only operation against a few elements, it wasn’t a big deal. For the jQuery, it’s just a selector-style query for which the path is much like simply dealing with the DOM.

The methods, shown in Figure 5 for fetching are pretty straightforward: Because the container is public, I don’t need to deal with a proxy or with any special authentication.

Figure 5 Fetch Methods:

Silverlight

WebClient StorageClient = new WebClient();
          StorageClient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(GetBlobsCompleted);
          StorageClient.DownloadStringAsync(new Uri(AZURE_STORAGE_URL, UriKind.Absolute));

Android

public InputStream GetBlobs()        {
         HttpURLConnection uc;
         InputStream returnStream=null;
try{
URL u = new URL(AZURE_STORAGE_URL);
uc = (HttpURLConnection) u.openConnection(); //u.openConnection(proxy);
uc.setRequestProperty("Accept", "*/*");
uc.setRequestProperty("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7");
uc.setRequestProperty("Accept-Language", "en-us,en;q=0.5");
uc.setRequestProperty("Keep-Alive", "300");    
uc.setRequestProperty("ucection", "keep-alive");   
returnStream = uc.getInputStream();

jQuery

$(document).ready(function () {
  $.ajax({
    type: "GET",
    url: "https://jofultz.blob.core.windows.net/filecabinet?comp=list",
    dataType: "xml",
    success: RenderData
  });
});

For both Silverlight and jQuery I provide a callback to handle the response, as the request is made asynchronously and the response is passed to the callback to handle. For Android, the request is issued synchronously. For jQuery and Silverlight, I’ll need one more supporting method in each of them to handle the data and get it either in a consumable format or, in the jQuery case, render it directly. 

Next, I need to handle the response in each example. I’ll go through each one to make each of the samples as clear as possible. Starting with the Windows Phone 7 example, I implement the GetBlobsCompleted method. I use LINQ syntax to tease the XML into an enumerable list of my custom object, as shown in Figure 6.

Figure 6 GetBlobsCompleted Method

IEnumerable<StorageImage> ImageList = from Blob in xDoc.Descendants("Blob")



select new StorageImage()



  {



    Name = Blob.Descendants("Name").First().Value,



    Url = Blob.Descendants("Url").First().Value,



    Image = new BitmapImage(



      new Uri(Blob.Descendants("Url").First().Value, UriKind.Absolute)) 



  };







MainPage.ImageInfoList.Clear();



foreach (StorageImage CurImg in ImageList)



{



  MainPage.ImageInfoList.Add(CurImg);



}

I have to move the objects into an ObservableCollection<StorageImage>. I first clear the list, then loop through the LINQ result and add the objects to my ObservableCollection. Because the collection is in the DataContext and the ListBox is bound to the DataContext, it automatically picks up the changes and updates the contents of the ListBox. 

Moving on to Java/Android, I don’t have something as nice as LINQ to use, so I’m stuck doing more work teasing the data out of the DOM manually. The method MarshalToBlobInfos will take an XML Document object and parse it, building an ArrayList of BlobInfos.

This looks much like any other DOM-style access in .NET, JavaScript and so on, as you can see in Figure 7.

Figure 7 The MarshalToBlobInfos Method

public ArrayList<BlobInfo> MarshalToBlobInfos(Document doc)



  {



    ArrayList<BlobInfo> returnBlobs = new ArrayList<BlobInfo>();







  try {



    Element root = doc.getDocumentElement();



    NodeList items = root.getElementsByTagName("Blob");



    for (int idxBlobs=0;idxBlobs<items.getLength();idxBlobs++){



      BlobInfo blob = new BlobInfo();



      Node item = items.item(idxBlobs);



      NodeList blobProperties = item.getChildNodes();



      for (int idxProps=0;idxProps<blobProperties.getLength();idxProps++){



        Node property = blobProperties.item(idxProps);



        String name = property.getNodeName();



          if (name.equalsIgnoreCase("Name"))



            blob.Name = property.getFirstChild().getNodeValue();



          } else if (name.equalsIgnoreCase("Url")){



              blob.Url = property.getFirstChild().getNodeValue();



          }



      }



      returnBlobs.add(blob);



    }



  } catch (Exception e) {



      throw new RuntimeException(e);



  } 



  return returnBlobs;



  }

Finally, I write the jQuery used to work through the result and render the needed HTML. It’s by far the shortest bit of code. But, depending on comfort level, it may be the most obtuse:

function RenderData(xml) {







  $(xml).find("Blob").each(



    function () {



      $("#output").append("<img margin=50 height=70 width=60 src=" + 



      $(this).find("Url").text() +



      " title=" + $(this).find("Url").text() + " id=" + 



      $(this).find("Name").text() + ") />&nbsp;");







  });   



$("img").each(



  function () {



    $(this).click(



      function () {



        $("#zoomview").attr("src", $(this).attr("src"));



      });



  });



}

This asks for each “Blob” element of the XML; for each I write an <img /> tag into the element, whose id is assigned the value of “output.” I use the similar selector construct to pull out the value of each element within the current “Blob” element needed to properly render the <img /> tag. I then create a selector for each resulting <img /> element and add a click handler to it. 

So far my Silverlight code makes a REST call to Azure Storage, parses the result and displays the filmstrip. The final step is to add a click handler for the filmstrip to show the zoom view of the image. I add a handler for SelectionChanged that grabs the currently selected StorageImage and assigns the Image control Source property the value of its Image property:

private void ImageList_SelectionChanged(object sender, SelectionChangedEventArgs e)



{



  ListBox lb = (ListBox)sender;



  StorageImage img = (StorageImage) lb.SelectedItem;



  ImageViewer.Source = img.Image;



}

That’s it for Silverlight on Windows Phone 7. Android will take more work.

Thanks to the REST interface of Azure Storage and the straightforward XML response, it’s simple to make the call and parse the results whether I’m using .NET, JavaScript or, in this case, Java on Android. With the two main supporting methods in place, I’ll add the code to the onCreate method of the Activity. Within the Activity, after the line to restore existing state, I’ll add the lines of code to make the call to Azure Storage and parse the results:

InputStream blobstream = GetBlobs();



DocumentBuilder docBuilder = 



  DocumentBuilderFactory.newInstance().newDocumentBuilder();



Document doc = docBuilder.parse(blobstream);



BlobList = MarshalToBlobInfos(doc);

If the code were to run at this point I’d have no UI, but I want the filmstrip from the Windows Phone 7 example. The next step is to hook up the UI elements. I’ll call setContentView, passing in a resource id. In this case, it’s the resource id for the main.xml.

If I needed to change the view of an activity, I could call it passing in a different resource. In the previous example of the main.xml markup, the Gallery and the ImageView have the ids of Thumbnails and ZoomView, respectively. I’ll use those ids to reference the widgets (controls) and assign a local variable for each reference. I’ll place the following code right after the previous code:

setContentView(R.layout.main);    



mZoomView = (ImageView)findViewById(R.id.ZoomView);    



mThumbnails = (Gallery) findViewById(R.id.Thumbnails);

Now I need to create an adapter to help retrieve, format and lay out each item in the collection. Before I can set the adapter for the Thumbnails Gallery I have to create one. I add a new class to the project named ImageAdapter, which extends BaseAdapter. When I set it as the adapter for the Activity it should call count and subsequently call getView for each item passing in the position of the item, which I will use as the ArrayList index. I’ll pass a pointer to the Activity into the ImageAdapter, because I’ll need contextual information—in particular, I’ll need the ArrayList that represents the images. The declaration and constructor for the ImageAdapter look like this:

public class ImageAdapter extends BaseAdapter 



{    



  private Context mContext;    



  private ArrayList<BlobInfo> mBlobList=null;



  public ImageAdapter(Context c) 



  {      



    mContext = c; 



    mBlobList = ((AzureImageViewer) mContext).BlobList;



   



  }    



  public int getCount() 



  {        



    int count = mBlobList.size();



    return count;







  }

In the getView method, implemented as part of the adapter, I fetch the image, create a thumbnail and save the original image to the related BlobInfo object. For an actual implementation, one would only want to pre-fetch a number of images and clean them up as the user scrolled, keeping a moving window of available images based on the position of the filmstrip. The thumbnails would need to be fetched by a background thread much like the pattern required in the Silverlight and jQuery examples.

Additionally, the fetching code for the item specifically might be better placed in the getItem override. With those caveats, Figure 8 shows the getView implementation.

Figure 8 The getView Implementation

public View getView(int position, View convertView, ViewGroup parent) 



{



  ImageView imageView;



  if (convertView == null) 



  {  



    imageView = new ImageView(mContext);



    imageView.setLayoutParams(new Gallery.LayoutParams (85, 70));



    imageView.setScaleType(ImageView.ScaleType.FIT_XY);



    imageView.setPadding(4, 4, 4, 4);



  } 



  else 



  {



    imageView = (ImageView) convertView;



  }



  BlobInfo CurrentBlob = mBlobList.get(position);



        



  if (CurrentBlob.ImageBitmap == null)



  {



    Bitmap bm = getImageBitmap(CurrentBlob.Url);



    imageView.setImageBitmap(bm);



    CurrentBlob.ImageBitmap = bm;



  }



  else



  {



    imageView.setImageBitmap(CurrentBlob.ImageBitmap)



  }     



  return imageView;    



}

The initial state of the view is done by the first conditional statement by either configuring it or by using a view passed to the function. By the time the if-else is passed, the view is ready—but I still don’t have the image. To help with that, I use the position parameter to fetch the appropriate BlobInfo object and then the URL property to fetch the image (in my case they’re all .jpgs), as shown in Figure 9.

Figure 9 Fetching the Image

private Bitmap getImageBitmap(String url) { 



  Bitmap ImageBitmap = null; 



  try { 



    URL ImageURL = new URL(url); 



    URLConnection ImageConnection = ImageURL.openConnection(); 



    ImageConnection.connect(); 



    InputStream ImageStream = ImageConnection.getInputStream(); 



    BufferedInputStream BufferedStream = new BufferedInputStream(ImageStream); 



    Log.e("Available buffer: ", String.valueOf(BufferedStream.available()));



    ImageBitmap = BitmapFactory.decodeStream(BufferedStream); 



    BufferedStream.close(); 



    ImageStream.close(); 



 } catch (Exception e) { 



    Log.e("Error getting bitmap", e.getMessage()); 



 } 



 return ImageBitmap; 



}

To fetch the image, I create a new connection based on the URL, then create a BufferedStream to pass to the BitmapFactory.decodeStream method. However, there seems to be an issue with decodeStream and using the BufferedStream object. For this sample I’m going to go ahead and use it, knowing that nothing I’ve tested that is 1MB or greater has worked; what’s worse, it just silently fails. 

The best way to avoid these issues is to write code to manually read the input stream, then pass that to the BitmapFactory object. Once the BitmapFactory has done its work, I return the bitmap, set the ImageBitmap and assign the bitmap to the related BlobInfo object ImageBitmap property. If I’ve already fetched it, I just use the current value in the BlobInfo object. 

When it runs I should see a filmstrip of images; as of yet, though, I can’t zoom into an image, and nothing happens upon selecting a thumbnail. So I’ll add a click listener for the thumbnails and, based on the position of the selected item, reference the BlobInfo ArrayList and use the resulting BlobInfo ImageBitmap property as the parameter to the ZoomView (of type ImageView) setImageBitmap call:

mThumbnails.setOnItemClickListener(new OnItemClickListener()



{



    public void onItemClick (AdapterView<?> parent, View v, int position, long id)



    {



      BlobInfo CurrentBlob = BlobList.get(position);



      mZoomView.setImageBitmap(CurrentBlob.ImageBitmap);



    }



  });

Universal Donor

The Android sample was the heaviest implementation, as compared to the quick and simple Windows Phone 7 and jQuery examples. That could be due to my familiarity level, but looking at the code I had to write across the three, I think there’s more to it than just comfort level. The fact is that using Azure breathes life and power into applications, regardless of the device platform.

Interfacing with Azure Storage couldn’t be much simpler without having someone do it for you. In this case, the access came down to fetching a list via REST and then issuing a subsequent HTTP Get based on the content of the return to fetch the item directly.


Joseph Fultz is a software architect at AMD, helping to define the overall architecture and strategy for portal and services infrastructure and implementations. Previously he was a software architect for Microsoft working with its top-tier enterprise and ISV customers defining architecture and designing solutions.