Saturday, March 27, 2010

Creating a Connect-Request in HealthVault

I've been doing a lot of work with Microsoft HealthVault at my job lately. I did some experimental work with the platform when I first started working there and since then, I've sort of been the team's HealthVault expert. It's been fun learning all about it and challenging as well, since most of the HealthVault libraries, tutorials, etc are centered around .NET (we use Java). So HealthVault is something I think would be fun to blog about.

This blog post will be about how to use what are called connect-requests in HealthVault. It assumes that you already have some knowledge of HealthVault from a developer's perspective. It includes Java code samples that use the JAX-B classes from the HealthVault Java Library.

Connect-requests are used by non web-based applications to create a connection to a HealthVault record. The process must only be completed once--not every time the application wants to access the record. They work like this:



1 The application prompts the user for the following information:

  • Friendly name - This can be anything, but should be the name that's on the HealthVault record.

  • Question - A question of the user's choosing (such as "What high school did I go to?").

  • Answer - The answer to the above question.

2 The application uses the above information, along with an external-id, to create a connect-request. The external-id can be any value that uniquely identifies the connect-request (the current time in milliseconds works fine). This value must be saved somewhere, as the application will need to use it again later (see step 5). Using these four bits of information, the application sends the request to HealthVault:
//create the request
CreateConnectRequestRequest request = new CreateConnectRequestRequest();
request.setExternalId(System.currentTimeMillis() + "");
request.setQuestion("Question?");
request.setAnswer("Answer");
request.setFriendlyName("Joe Smith");

//send the request / get the response
SimpleRequestTemplate srt = new SimpleRequestTemplate(ConnectionFactory.getConnection());
CreateConnectRequestResponse response = (CreateConnectRequestResponse) srt.makeRequest(request);
String identityCode = response.getIdentityCode();





Note:
Because we're using the JAX-B request classes, be sure to use
com.microsoft.hsg.methods.jaxb.SimpleRequestTemplate
and not
com.microsoft.hsg.request.SimpleRequestTemplate


3 HealthVault returns an identity-code, which is a sequence of 20 random letters separated into five groups of four:
DHLE-ELHP-AQLG-TLPZ-PQKD
The application must show this to the user. It should also show (what I call) the patient connect URL. The user will have to visit this URL in order to validate the connect-request:
https://account.healthvault-ppe.com/patientwelcome.aspx

Remove the "-ppe" when going live of course.

4 The user visits the patient connect URL in a web browser. This page will step the user through a process, requiring her to (1) login to her HealthVault account, (2) enter the identity-code, (3) enter the question/answer, and (4) choose which record in her account to grant the application access to.

5 Once the user has done this, the application is able to retrieve the person-id and record-id of the user's HealthVault record:
String externalId = //retrieve the external-id you saved in step 2
GetAuthorizedConnectRequestsRequest request = new GetAuthorizedConnectRequestsRequest();
SimpleRequestTemplate srt = new SimpleRequestTemplate(ConnectionFactory.getConnection());
GetAuthorizedConnectRequestsResponse response = (GetAuthorizedConnectRequestsResponse) srt.makeRequest(request);
for (ConnectRequest cr : response.getConnectRequest()) {
if (cr.getExternalId().equals(externalId)) {
String personId = cr.getPersonId();
String recordId = cr.getRecordId();
//save to persistent storage (like a database)
break;
}
}
However, the application has no way of knowing when the user will approve the application (when she completed step 4). So, the application must continually poll HealthVault for newly approved connect-requests (e.g. a separate thread which calls GetAuthorizedConnectRequests every 30 seconds or so).




Note:
The CreateConnectRequest method has a "call-back-url" parameter, which is a URL that HealthVault is supposed to call when the connect-request is validated by the user. However, at the time of this writing, it is not supported.

Monday, March 22, 2010

Mac OS X Mouse Acceleration

If the mouse acceleration settings of Mac OS X ever frustrate you, check out the Mouse Acceleration Preference Pane. This is a utility created by Christian Zuckschwerdt which lets you adjust these settings to your liking.

Apple changed around OS X's mouse API when version 10.6 was released, which made existing mouse acceleration tools useless. However, Christian just recently released an updated version supporting 10.6! My hand feels less cramped already...

Sunday, March 14, 2010

Working with Scala and Maven

In order to get Maven to properly recognize Scala code, there are are a number of steps you must take. Included below are pom.xml samples, along with explanations.

1. Name your source directories properly:
<project><build>

<sourceDirectory>src/main/scala</sourceDirectory>
<testSourceDirectory>src/test/scala</testSourceDirectory>

</build></project>

2. Add the scala-tools.org repositories.

These are required in order to download the necessary Scala dependencies (see step #3):
<project>
<repositories>
<repository>
<id>scala-tools.org</id>
<name>Scala-tools Maven2 Repository</name>
<url>http://scala-tools.org/repo-releases</url>
</repository>
</repositories>

<pluginRepositories>
<pluginRepository>
<id>scala-tools.org</id>
<name>Scala-tools Maven2 Repository</name>
<url>http://scala-tools.org/repo-releases</url>
</pluginRepository>
</pluginRepositories>
</project>

3. Add the appropriate dependencies:
<project><dependencies>

<!--
This contains the scala compiler, which Maven will use to compile your code and run your unit tests.
-->
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>2.7.7</version>
</dependency>

<!--
This is Scala's unit testing framework. It's also possible to use JUnit, but when in Rome, right?
-->
<dependency>
<groupId>org.scalatest</groupId>
<artifactId>scalatest</artifactId>
<version>1.0</version>
<scope>test</scope>
</dependency>

<!--
If you want to use scalatest, unfortunately you also need to include JUnit as a dependency (see step #5).
-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.1</version>
<scope>test</scope>
</dependency>

<dependencies></project>

4. Add the scala-tools plugin:
<project><build><plugins>

<plugin>
<groupId>org.scala-tools</groupId>
<artifactId>maven-scala-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>

</plugins></build></projects>

5. Add the @RunWith annotation to each unit test.

If you are using scalatest as your unit testing framework, you must trick Maven into thinking that your tests are JUnit tests. Otherwise, Maven will not run your tests:
import org.junit.runner.RunWith
import org.scalatest.junit.JUnitRunner
import org.scalatest.FunSuite

@RunWith(classOf[JUnitRunner])
class MyScalaTest extends FunSuite{
//...
}

Tip: If you're using Eclipse, you can right click on one of these unit tests and select "Run As > JUnit Test" to manually run the test.

Wednesday, March 10, 2010

XPath and Java

XPath is a domain specific language which is used to extract data from an XML document. It's supported by many different general purpose languages like C#, PHP, and Java. Take the following XML document for example:

<library>
<book>
<language>en</language>
<title>Solaris</title>
<author>Stanislaw Lem</author>
</book>
<book>
<language>fr</language>
<title>Le Petit Prince</title>
<author>Antoine de Saint-Exupéry</author>
</book>
<book>
<language>en</language>
<title>Dune</title>
<author>Frank Herbert</author>
</book>
</library>

The following XPath query retrieves the titles of all English-language books:

/library/book[language='en']/title

Java makes working with XPath (and XML in general) kind of complicated, since many different classes are involved. First, the XML document must be loaded into a DOM (Document Object Model).

StreamSource source = new StreamSource(new File("books.xml"));
DOMResult result = new DOMResult();
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.transform(source, result);
Node documentRoot = result.getNode();

This means that the XML text is read into memory and organized into a tree of nodes where each tag is an element node. The top element node would be the <library> element, which would have three child element nodes (<book>), and so on.



To demonstrate the power of XPath, this is what Java code might look like if XPath did not exist. The programmer would have to manually iterate through the entire DOM to get what she needed.

List<String> englishTitles = new ArrayList<String>();
Node books = documentRoot.getFirstChild();
if (books.getNodeName().equals("library")){
for (int i = 0; i < books.getChildNodes().getLength(); ++i){
Node book = books.getChildNodes().item(i);
if (book.getNodeName().equals("book")){
boolean english = false;
String title = null;
for (int j = 0; j < book.getChildNodes().getLength(); ++j){
Node bookChild = book.getChildNodes().item(j);
if (bookChild.getNodeName().equals("language") &&
bookChild.getTextContent().equals("en")){
english = true;
}
if (bookChild.getNodeName().equals("title")){
title = bookChild.getTextContent();
}
}
if (english && title != null){
englishTitles.add(title);
}
}
}
}
for (String title : englishTitles){
System.out.println(title);
}

As you can see, this is very very tedious and error prone! XPath is the better solution by far:

XPath xpath = XPathFactory.newInstance().newXPath();
NodeList nodeList = (NodeList)xpath.evaluate("/library/book[language='en']/title",
documentRoot, XPathConstants.NODESET);
for (int i = 0; i < nodeList.getLength(); ++i){
Node node = nodeList.item(i);
System.out.println(node.getTextContent());
}

Namespaces

XML documents often use namespaces. These are sort of like Java packages--they group related elements together and prevent name collisions from occurring. Let's say that each <language> element belonged to a namespace:

<book>
<language xmlns="http://translate.google.com">en</language>
<title>Solaris</title>
<author>Stanislaw Lem</author>
</book>

Note: While namespaces technically can be anything (like "abc123" for example), they should be globally unique. There's no way to enforce this, so the convention is to use a URI belonging to the person or company creating the namespace. For example, if Oracle wants to use a namespace, they can be fairly certain that no one else in the entire world is using one starting with "http://www.oracle.com".


To make Java aware of namespaces,a NamespaceContext object must be created and added to the XPath object.

XPath xpath = XPathFactory.newInstance().newXPath();
xpath.setNamespaceContext(new NamespaceContext() {
public String getNamespaceURI(String prefix) {
if ("tr".equals(prefix)){
return "http://translate.google.com";
}
return null;
}
public Iterator getPrefixes(String uri) {
return null;
}
public String getPrefix(String uri) {
return null;
}
});

This will assign the prefix "tr" to the namespace "http://translate.google.com". The prefix can be anything, but the namespace must match the one in the XML document.

NodeList nodeList = (NodeList)xpath.evaluate("/library/book[tr:language='en']/title",
documentRoot, XPathConstants.NODESET);
for (int i = 0; i < nodeList.getLength(); ++i){
Node node = nodeList.item(i);
System.out.println(node.getTextContent());
}

To learn more about XPath, you can visit w3schools.com.

Tuesday, March 9, 2010

Dropbox


I just found out about this cool service called Dropbox, which I thought I'd write about. I read a blurb about it in the March issue of Linux Journal.

Dropbox is a free service that lets you store files online. That sounds pretty boring. But it's more than just a free FTP server. What happens is, you install a small app on your computer, which creates a special "dropbox" folder in your home directory (or in My Documents if you're using Windows). The app monitors this folder for any changes and syncs these changes with the Dropbox server. For example, when you copy a file (Word document, MP3, whatever) to this folder, it will immediately upload it to your Dropbox account. If you delete a file, it will delete it from your account.

But the really cool thing is that you can connect multiple computers to your account by installing the Dropbox application on each one (there are Windows, Mac, Linux, and iPhone versions). So if you add a file to your Dropbox folder on your desktop PC, it will immediately download to your MacBook laptop, Linux Netbook, and whatever else.

Thursday, October 22, 2009

An Amazon Affiliate Tutorial

Ok, so I'm a little behind the times. Amazon's Affiliate Program has been around for a while--since 1996 to be exact. Everyone and their grandma must have an account by now, making millions off sales of "The Secret" that they linked to on their blog (this is actually the secret that the book talks about). But incase you happen to be Amish, here's a short tutorial on the whole process of signing up for an account and building affiliate links.

1. Visit https://affiliate-program.amazon.com/ and click the "Join now for FREE!" button. It requires that you create an Amazon account first if you don't already have one.



2. It then asks you for your contact information and has some questions about the website/blog where you'll be putting your affiliate links.



3. And that's all the information they need to get your account set up. You don't even have to submit your payment information (although, you'll want to do this eventually...after all, making a few bucks is why you're here, right?). As you can see in the screenshot, Amazon assigns you a unique "Associates ID". This important identifier will be stuffed into all the affiliate URLs you create so that Amazon knows who give money to when a sale is made. To start making links, click the "Learn More" link in the "Product Links" box.



4. It's really easy to create affiliate links. It just takes a few clicks of the mouse and some copy and pasting. First, search for the product you want to link to. I chose a book I recently read.



5. Next, find the product in the search results and click the "Get Link" button.



6. This will take you to the page that lets you build your link. There's a lot of options here you can play with, so take some time to explore this page on your own. Once you're done crafting the link to your liking, copy the HTML code in the "step 3" box and paste it on your site. It's no secret--it's that simple!

Tuesday, October 6, 2009

Using Magpie to parse Blogger feeds

I recently redesigned my website and one thing I changed was putting my blog on the front page instead of just linking to it. But what's cool (at least, according to my own geeky tastes) is that my blog is hosted on Blogger--not on my website! In this post, I'm going to walk through how I did this.

1. Blogger setup
First, you need to make sure your Blogger feeds are configured to include the full content of each blog post (as opposed to just the first paragraph or whatever). I think this is the default setting, but to make sure, to go the Settings page and click on the "Site Feed" tab. The "Allow Blog Feeds" option should be set to "Full".



2. Atom feed URL
Now, you must get the URL of your blog's Atom feed. Go to your blog's homepage and view the source (in Firefox, this is under "View > Page Source"). Look for a "link" tag that looks like the one below, and grab the value of its "href" attribute.
<link rel="alternate" type="application/atom+xml" title="mangstacular - Atom" href="http://mangstacular.blogspot.com/feeds/posts/default" />

Note: In this tutorial, I use the Atom feed. The RSS feed also has all the same information--it's just arranged differently.


3. Magpie setup
Download Magpie. This is a wonderfully easy-to-use RSS/Atom parser written in PHP which we'll use to parse the Atom feed.

You'll want to configure Magpie to cache the Atom feed so that it only downloads it when your blog changes in some way (i.e. when there's a new post or a new comment). This way, your website won't have to download the feed from Blogger every time someone visits your page. Open the "rss_fetch.inc" file and add these two lines somewhere at the top:
define('MAGPIE_CACHE_ON', true);
define('MAGPIE_CACHE_DIR', 'cache');

This will turn on caching and instruct Magpie to save the cached Atom file in the directory you specify.

Note: Be sure that the permissions of the cache directory allow your web server to write to it. The way you do this varies from server to server, based on the user that your PHP process runs under, but here are the commands that I had to run:
chmod 775 cache
chgrp web cache

What you do NOT want to do is set the folder to be globally writable. While this would work, it would also allow anyone on the Internet to write to that directory--not a good thing.


4. Parse the Feed
Now you're ready to write the code that fetches and parses the feed. Simply calling Magpie's "fetch_rss" function will parse the feed and return all the data in an associative array (despite "rss" being in the function name, it will also parse Atom feeds). No need to deal with any XML. Below is some sample code.

Note: There are a couple quirks, which may be Blogger-specific--be sure to read the code comments.

require_once('magpierss/rss_fetch.inc');

$atom = fetch_rss('http://mangstacular.blogspot.com/feeds/posts/default');
foreach ($atom->items as $item){
//var_dump($item); //see all the stuff that's in each item

$date = date('F j, Y', strtotime($item['published']));
$title = $item['title'];
$content = $item['atom_content']; //no need to run html_entity_decode() or anything
$url = $item['link'];

//because there are two <link> tags whose "rel" attributes are the same...
//...it stuffs the "href" attributes from both tags into this one string...
//...so you must extract the URL you want...
//...which in my case is the URL to the comments page
$commentsUrl = substr($item['link_replies'], strpos($item['link_replies'], 'https'));

$numberOfComments = $item['thr']['total'];

//generate HTML for the entry
//...
}


And now it looks like you're running fancy Wordpress software! ;)