Thursday, December 18, 2008

BlazeDS and secure Web Service access

In a previous post, I described how to use Flex/BlazeDS to a access remote Web Services.
This time, I am explaining how to access a secure Web Service that requires basic authentication using the same mechanism. This involves additional changes in the configuration files.

My goal is to create flex components that access ICW Lifesensor public Web services.
The additional complication is that the access to wsdl file required authentication over HTTPS.

Fortunately, I have the login and password of a Lifesensor Account (patient), so I can use them
to access the Reporting Web Services in order to retrieve medical data entries. More information about the Lifesensor APIs and Web services are available on the ICW Developer Network.

To illustrate my point, I will use a very simple Web Service call getVersion that return some general information about the web services such as the Axis version and build date (Lifesensor uses the open source Apache Axis framework to provide Web Services).

In the wsdl file for Version, the port description shows that the getVersion operation does not have any parameter, so the call to the Web Service will be straightforward:
<wsdl:porttype name="Version">
 <wsdl:operation name="getVersion">
  <wsdl:input message="impl:getVersionRequest" name="getVersionRequest"></wsdl:input>
  <wsdl:output message="impl:getVersionResponse" name="getVersionResponse"></wsdl:output>
  </wsdl:operation>
</wsdl:porttype>

BlazeDS offers a Proxy to access remote servers. This is necessary, if you do not have a crossdomain.xml file on your remote server. As a result, there will be two hops. One from the shockwave component on the client to the Proxy, the other one from the Proxy to the remote server where the Web Services reside.

For security reasons, both bops have to be secure, as a result, the initial SWF access and loading has to be done through HTTPS. In my case, my application (and the BlazeDS proxy) is served by Tomcat 6.0 that has been configured for SSL.

The first configuration change is in the proxy-config.xml. Besides the fact that the URL is now using HTTPS protocol, you will need also to specify the soap URL instead of using a wildchard in order to avoid a RPC Fault since "a destination that allows multiple domains or ports does not allow authentication".

Also, since LifeSensor is using basic access authentication, the easiest way to avoid the pop-up window from your browser asking you for the login and password (especially for the first hop, which is not relevant), is to set them in the proxy-config.xml initially via remote-user and remote-password tags.
     <destination id="ws-lifesensor-version">
       <properties>
           <wsdl>https://record2.us.lifesensor.com/phr/services/Version?wsdl</wsdl>
           <remote-username>?????</remote-username>
           <remote-password>?????</remote-password>
           <soap>https://record2.us.lifesensor.com/phr/services/Version</soap>
       </properties>
       <adapter ref="soap-proxy"/>
   </destination>

The MXML flex file is not very different from a Web Service access with no authentication. The following code is just specific to the Lifesensor Web Service API:
<mx:Script>
     <![CDATA[
       ...
       private function getData():void { webService_LS_Version.getVersion.send();}   
       ...
    ]]>
   </mx:Script>
   <mx:WebService id="webService_LS_Version" destination="ws-lifesensor-version" useProxy="true">
       <mx:operation name="getVersion"
               resultFormat="object"
               result="getData_result(event);"
               fault="getData_fault(event);">
       </mx:operation>
   </mx:WebService>

Calling the Version Web Service from LifeSensor (via an application on https://localhost:8443/) returns the following text:
"Apache Axis version: 1.4
Built on Apr 22, 2006 (06:55:48 PDT)"

In addition to this, my recommendations will be to use Flex remote debugging and a HTTP debugging proxy such as Charles or Fiddler which can be very handy to understand and debug AMF and SOAP based HTTP wrapped requests.

Also, Flex Builder 3.0 has very nice Web Service Introspection tool. Unfortunately, you will need to have a cross domain file on the server you want to introspect or have LifeCycle Data service to use the generated proxies. Apparently, if you only use BlazeDS, there are no direct ways to use the generated code out of the box. However, you can use some of the generated classes to store some of the data you obtain from the Web Services. This will be the topic of my next post.

Wednesday, November 19, 2008

Flex z-index and Liferay Portal

We recently encountered an issue when embedding Flex/Flash applications in Liferay Portlets.

The shockwave (.swf) file was showing on top of the liferay navigation menu:













The usual solution is to specify the z-index for the div layers.
There are even some very cool things you can do with Flex overlay.

Liferay however is a third party portal platform and if you don't want to have to change the source code or extend Liferay, a quick fix is to use the wmode argument for the embedded flex application:

<div>
   <embed wmode="transparent" src="<%= request.getContextPath() %>/flex/clinical_data.swf" height=250 width=500>
</div>

You just have to redeploy your portlet and now the menu appears on top of your portlet:

Thursday, November 13, 2008

Liferay Portlet using BlazeDS

In my previous post, I explained why and how I used BlazeDS, a server-based Java remoting and web messaging technology, to call remote Web Services easily from Adobe Flex applications.

In this post I explain how to create a Liferay portlet that uses Flex and BlazeDS.

Creating the Liferay Portlet

Creating a new portlet is straightforward. Under ./liferay-plugins-sdk-5.1.1/portlets at the prompt I just typed the command: create messier_object "Messier Object WS". As a result, a messier_object-portlet folder is created with the skeleton of a working portlet (the first argument of create is the name of the portlet (always postfixed with '-portlet'), the second argument is the title of the portlet).

I then modified the category name of messier_object-portlet/docroot/WEB-INF/liferay-display.xml to ICW.Test.

<display>
   <category name="ICW.Test">
      <portlet id="messier_object">
   </portlet>
</category>

I then added the Flex code by copying my testing Flex Application Test_Flex_WS_messier.mxml under the docroot folder.

Integrating the target shockwave file in the view.jsp file is also straightforward:
<div>
   <embed src="<%= request.getContextPath() %>/Test_Flex_WS_messier.swf" heigth=350 width=350>
</div>
Adding BlazeDS Libraries and Configuration Files

I then added a set of 10 jar files (backport-util-concurrent.jar to flex-messaging-remoting.jar) that came with the turnkey BlazeDS installation sample code inside the WEB-INF/lib folder.

In addition to this, I had to copy the four BlazeDS configuration files:
messaging-config.xml, proxy-config.xml, remoting-config.xml, services-config.xml.

The services defined in these files are generic and can be reuse if you want to access remote data either through Messaging, HTTService, WebService or RPC/AMF remote procedure calls.

Only proxy-config.xml contains a specific web service destination (ws-sesame) to access astronomical data for the application.









Content of messaging-config.xml:

<?xml version="1.0" encoding="UTF-8"?>
<service id="message-service" class="flex.messaging.services.MessageService">
<adapters>
<adapter-definition id="actionscript" class="flex.messaging.services.messaging.adapters.ActionScriptAdapter" default="true" />
<adapter-definition id="jms" class="flex.messaging.services.messaging.adapters.JMSAdapter"/>
</adapters>
<default-channels>
  <channel ref="my-streaming-amf"/>
  <channel ref="my-polling-amf"/>
</default-channels>
</service>

Content of proxy-config.xml:

<?xml version="1.0" encoding="UTF-8"?>
<service id="proxy-service" class="flex.messaging.services.HTTPProxyService">

<properties>
<connection-manager>
<max-total-connections>100</max-total-connections>
<default-max-connections-per-host>2</default-max-connections-per-host>
</connection-manager>
<allow-lax-ssl>true</allow-lax-ssl>
</properties>

<default-channels>
<channel ref="my-http"/>
<channel ref="my-amf"/>
</default-channels>

<adapters>
<adapter-definition id="http-proxy" class="flex.messaging.services.http.HTTPProxyAdapter" default="true"/>
<adapter-definition id="soap-proxy" class="flex.messaging.services.http.SOAPProxyAdapter"/>
</adapters>

<destination id="DefaultHTTP">
<properties>
</properties>
</destination>

<destination id="ws-sesame">
<properties>
<wsdl>http://cdsws.u-strasbg.fr/axis/services/Sesame?wsdl</wsdl>
<soap>*</soap>
</properties>
<adapter ref="soap-proxy"/>
</destination>

</service>


Content of remoting-config.xml:


<?xml version="1.0" encoding="UTF-8"?>
<service id="remoting-service" class="flex.messaging.services.RemotingService">
<adapters>
<adapter-definition id="java-object" class="flex.messaging.services.remoting.adapters.JavaAdapter" default="true"/>
</adapters>
<default-channels>
<channel ref="my-amf"/>
</default-channels>
</service>

Content of services-config.xml:


<?xml version="1.0" encoding="UTF-8"?>
<services-config>

<services>
  <service-include file-path="remoting-config.xml" />
  <service-include file-path="proxy-config.xml" />
  <service-include file-path="messaging-config.xml" />
  <default-channels>
     <channel ref="my-amf"/>
  </default-channels>
 </services>

<channels>

  <channel-definition id="my-streaming-amf" class="mx.messaging.channels.StreamingAMFChannel">
      <endpoint url="http://{server.name}:{server.port}/{context.root}/messagebroker/streamingamf" class="flex.messaging.endpoints.StreamingAMFEndpoint"/>
  </channel-definition>

  <channel-definition id="my-amf" class="mx.messaging.channels.AMFChannel">
      <endpoint url="http://{server.name}:{server.port}/{context.root}/messagebroker/amf" class="flex.messaging.endpoints.AMFEndpoint"/>
      <properties>
          <polling-enabled>false</polling-enabled>
      </properties>
  </channel-definition>

  <channel-definition id="my-secure-amf" class="mx.messaging.channels.SecureAMFChannel">
      <endpoint url="https://{server.name}:{server.port}/{context.root}/messagebroker/amfsecure" class="flex.messaging.endpoints.SecureAMFEndpoint"/>
  </channel-definition>

  <channel-definition id="my-polling-amf" class="mx.messaging.channels.AMFChannel">
      <endpoint url="http://{server.name}:{server.port}/{context.root}/messagebroker/amfpolling" class="flex.messaging.endpoints.AMFEndpoint"/>
      <properties>
          <polling-enabled>true</polling-enabled>
          <polling-interval-seconds>4</polling-interval-seconds>
      </properties>
  </channel-definition>

  <channel-definition id="my-http" class="mx.messaging.channels.HTTPChannel">
      <endpoint url="http://{server.name}:{server.port}/{context.root}/messagebroker/http" class="flex.messaging.endpoints.HTTPEndpoint"/>
  </channel-definition>

  <channel-definition id="my-secure-http" class="mx.messaging.channels.SecureHTTPChannel">
      <endpoint url="https://{server.name}:{server.port}/{context.root}/messagebroker/httpsecure" class="flex.messaging.endpoints.SecureHTTPEndpoint"/>
  </channel-definition>

</channels>

<logging>
  <!-- You may also use flex.messaging.log.ServletLogTarget -->
  <target class="flex.messaging.log.ConsoleTarget" level="Error">
      <properties>
          <prefix>[BlazeDS] </prefix>
          <includeDate>false</includeDate>
          <includeTime>false</includeTime>
          <includeLevel>true</includeLevel>
          <includeCategory>false</includeCategory>
      </properties>
      <filters>
          <pattern>Endpoint.*</pattern>
          <pattern>Service.*</pattern>
          <pattern>Configuration</pattern>
      </filters>
  </target>
</logging>

<system>
  <redeploy>
      <enabled>true</enabled>
      <watch-interval>20</watch-interval>
      <watch-file>{context.root}/WEB-INF/flex/services-config.xml</watch-file>
      <watch-file>{context.root}/WEB-INF/flex/proxy-config.xml</watch-file>
      <watch-file>{context.root}/WEB-INF/flex/remoting-config.xml</watch-file>
      <watch-file>{context.root}/WEB-INF/flex/messaging-config.xml</watch-file>      
      <touch-file>{context.root}/WEB-INF/web.xml</touch-file>
  </redeploy>
</system>

</services-config>
Do not forget to copy the definitions of the listener and the MessageBroker Servlet in your web.xml file.

Compiling the Flex Application


To compile the Flex application that will be encapsulated into the portlet, you will need to specify the portlet name as context root:
mxmlc -strict=true -show-actionscript-warnings=true -use-network=true \
-services=WEB-INF/flex/services-config.xml -context-root=messier_object-portlet \
-output=./Test_Flex_WS_messier.swf ./Test_Flex_WS_messier.mxml

Deploying the Portlet


To be able to access BlazeDS from the portlet, you will also need to copy the BlazeDS war file in tomcat under .\bundles\tomcat-6.0.16\webapps.

To compile and deploy the whole portlet just type the command 'ant deploy' at the prompt in the messier_object-portlet folder.

You can then add the portlet and test it:




















Friday, November 7, 2008

How to use BlazeDS for Web Service access

I was recently asked to investigate how quickly aggregate medical content from various sources in a portal environment. One path I explored was to use Adobe Flex as front-end technology and access remote web services such as the ones offered by ICW LifeSensor.

With Flex 3.0 you can easily use a Web Service directly from your MXML or ActionScript code, including .NET based web services.

However there are some restrictions. For security reasons, applications running in Flash Player on client computers can only access remote data sources if one of the following conditions is met:
  • Your SWF file is in the same domain as the remote data source.
  • A cross-domain policy file is installed on the web server hosting the data source.
  • You use a proxy and your SWF file is on the same server as the proxy.
Since the Web services I want to use are not under my control and I know they do not have a cross-domain policy files installed, the only solution left is for me to use a proxy.

The good news is that BlazeDS, in addition to add RPC capabilities to Flex, acts as a Proxy, so won't have to write my own!


Installing and trying BlazeDS
BlazeDS is really easy to install. I choose to download the turnkey version to start because it includes a runtime environment (Apache Tomcat) and lot of samples.


After download and unzip, the only things I had to do was to start the database for the samples (Hypersonic/HSQLDB) and start tomcat and point to http://localhost:8400/samples/. The "Take the test drive" of the tutorial contains a section (sample 2) using web services. The sample code is accessible in .\blazeds_turnkey_3-0-0-544\tomcat\webapps\samples\testdrive-webservice\src\main.mxml:

     <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"   backgroundColor="#FFFFFF">
 
       <mx:WebService id="srv" destination="ws-catalog" useProxy="true" showBusyCursor="true"/>
 
        <mx:DataGrid dataProvider="{srv.getProducts.lastResult}" width="100%" height="100%">
          <mx:columns>
                  <mx:DataGridColumn dataField="productId" headerText="Product Id"/>
                  <mx:DataGridColumn dataField="name" headerText="Name"/>
                  <mx:DataGridColumn dataField="price" headerText="Price"/>
           </mx:columns>
       </mx:DataGrid>
 
       <mx:Button label="Get Data" click="srv.getProducts()"/>
 
   </mx:Application>
The destination of the web service is defined in .\samples\WEB-INF\flex\proxy-config.xml:

   <destination id="ws-catalog">
       <properties>
           <wsdl>http://livecycledata.org/services/ProductWS?wsdl</wsdl>
           <soap>*</soap>
       </properties>
       <adapter ref="soap-proxy"/>
   </destination>

Installing and trying BlazeDS

The next step for me was to try to build a new Flex application from scratch
that uses a web service from an outside domain.
I decided to use one of my favorite free testing Web service,
the "CDS - Centre de Données astronomiques de Strasbourg"
located in Alsace, France which provides access to Astronomical data,
including Messier Objects.

Sesame is one of the apache axis based services hosted by CDS.
In the same way, this new service is declared in the proxy-config.xml file:

      <destination id="ws-sesame">
        <properties>
            <wsdl>http://cdsws.u-strasbg.fr/axis/services/Sesame?wsdl</wsdl>
            <soap>*</soap>
        </properties>
        <adapter ref="soap-proxy"/>
    </destination>

The Flex program is very easy to construct.
I have a list of Messier Objects in a combo box with their IDs (Mxxxx)
that are passed as argument for the SesameXML web service operation (see WDSL file).
The web service call indicated that BlazeDS is used as as proxy (useProxy="true")
and define two ActionScripts methods to handle the result coming back
from the remote service and to handle any error (respectively  getData_result and getData_fault).

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
    <mx:Script>
        <![CDATA[
            import mx.controls.Alert;
            import mx.rpc.events.ResultEvent;
            import mx.rpc.events.FaultEvent;
   import mx.utils.ObjectUtil;            
            // This software uses source code created at the Centre de Données astronomiques de Strasbourg, France.
            private function getData():void { webService.SesameXML.send();}
            private function getData_result(evt:ResultEvent):void {textArea.text = ObjectUtil.toString(evt.result);}
            private function getData_fault(evt:FaultEvent):void {Alert.show(evt.type);}
        ]]>
    </mx:Script>
    
    <mx:WebService id="webService" destination="ws-sesame" useProxy="true">
        <mx:operation name="SesameXML"
                resultFormat="object"
                result="getData_result(event);"
                fault="getData_fault(event);"> 
                <mx:request>
    <name>{messier_object.selectedItem.data}</name>
  </mx:request>
        </mx:operation>
    </mx:WebService>
 <mx:ApplicationControlBar dock="true">
        <mx:Button id="button" label="get Messier Data" click="getData();" />
        <mx:Spacer width="10%"/>
        <mx:ComboBox id="messier_object" width="200">
            <mx:dataProvider>
               <mx:ArrayCollection>
                  <mx:source>
                    <mx:Object label="Crab Nebula" data="M1"/>
                    <mx:Object label="Butterfly Cluster" data="M6"/>
                    <mx:Object label="Butterfly Cluster" data="M6"/>
                    <mx:Object label="Ptolemy Cluster" data="M7"/>
                    <mx:Object label="Lagoon Nebula" data="M8"/>
                    <mx:Object label="Wild Duck Cluster" data="M11"/>
                    <mx:Object label="Great Globular Cluster in Hercules" data="M13"/>
                    <mx:Object label="Eagle Nebula" data="M16"/> 
                    <mx:Object label="Omega Nebula" data="M17"/> 
                    <mx:Object label="Trifid Nebula" data="M20"/> 
                    <mx:Object label="Sagittarius Cluster" data="M22"/> 
                    <mx:Object label="Sagittarius Star Cloud" data="M24"/> 
                  </mx:source>
                </mx:ArrayCollection>
            </mx:dataProvider>
           </mx:ComboBox>
    </mx:ApplicationControlBar>
    <mx:TextArea id="textArea" editable="false" width="100%" height="100%" />
 
</mx:Application>
Building the SWF file

To build your shockwave executable file, it is important to indicate where the services
configuration file is located, so the BlazeDS stub is added to the *.SWF file
running in the browser inside the Flash Player and will make the connection
of the BlazeDS proxy.

   mxmlc -strict=true \
-show-actionscript-warnings=true \
-use-network=true \
-services=WEB-INF/flex/services-config.xml \
-context-root=samples \
-output=testdrive-webservice/main.swf testdrive-webservice/src/main.mxm
In fact, services-config.xml describes the different services that the web application is using:
 <services-config>
    <services>
        <service-include file-path="proxy-config.xml" />
        ...
   </services>
   ....
 </services-config>
You will also need to modify your ./docroot/WEB-INF/web.xml file by adding the definitions of the listener and the MessageBroker Servlet definition.
<web-app>
    <display-name>WebTest</display-name>
    <description>Application with Samples</description>

    <context-param>
        <param-name>flex.class.path</param-name>
        <param-value>/WEB-INF/flex/hotfixes</param-value>
    </context-param>

    <!-- Http Flex Session attribute and binding listener support -->
    <listener>
        <listener-class>flex.messaging.HttpFlexSession</listener-class>
    </listener>

    <!-- MessageBroker Servlet -->
    <servlet>
        <servlet-name>MessageBrokerServlet</servlet-name>
        <display-name>MessageBrokerServlet</display-name>
        <servlet-class>flex.messaging.MessageBrokerServlet</servlet-class>
        <init-param>
            <param-name>services.configuration.file</param-name>
            <param-value>/WEB-INF/flex/services-config.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>MessageBrokerServlet</servlet-name>
        <url-pattern>/messagebroker/*</url-pattern>
    </servlet-mapping>
 
</web-app>
Here is the result after querying information about Messier object (M1 - Crab Nebula):
The next task for me to see how to integrate BlazeDS in a portal environment
such as Liferay and explore authentication to Web Services and security features associated
to the use of BlazeDS.

Thursday, October 23, 2008

Health 2.0 - 2008 (San Francisco) - Day 2

Second day of the Health 2.0 2008 conference.
* the presentation from Sermo's CEO was quite impressive, especially in terms of number of US physicians that are part of their network.

3 Health 2.0 CEOs
  • JonathanBush, CEO AthenaHealth
    • process medical claims from doctors and put them into charts (EMR)
    • 40 millions different cases
    • in business for 10 years
    • try to make the doctor office paperless
    • process paper based documents (40,000 per day)
    • Statistics: doctors get 11% more revenue when using AthenaHealth
    • 89 pages of paper come every day for each doctor (mostly by Fax & Teleprinters)
    • business model: fee based (by the doctors)
  • Daniel Palestrant, MS, CEO Sermo
    • social network for doctors
    • company started 3 years ago
    • 90,000 US physicians 7,000 added each months
    • 20% of the US physicians at end of the year.
    • direct communication between physician and drug manufacturers (e.g. Pfizer) and the result is published for the whole Sermo community.
    • should be cash positive sometimes next year
    • extension to the international market planned in 2009
    • business model: no charge for the physician (in fact they pay the doctors to be part of the network), no advertising, get revenue from sponsors (e.g. drugs manufacturers)
    • work with FDA
    • Partnership with Bloomberg.
  • Kerry Hicks, CEO Healthgrades
    • provide rating and information on healthcare services
    • 5000 hospitals and most of the physicians, nursing homes etc ...
    • 13 millions piece of information coming each month
    • list 88 conditions
    • information on 40,000 prescription drugs
    • users: 55% women, 45% men
    • partnerhip with Google
    • 80% of the traffic comes from patients who have seen the patient in the last 30 days

Panel: Health 2.0 around the world

  • Video:
    • India: diagnosis over the phone including SMS (300 millions cell phones in india), 720 millions by 2012.
    • UK: UK: how to reduce healthcare cost
  • Thomas Liedtke, Emerging Health Care, ICW
    • statistics show that 20-30% of the patients get the wrong medication
    • OptiMed deployed for AOK, Germany
    • compliance control device
    • use iPhone to scan medication
  • Marlene WinField, SVP, NHS connecting for health
    • improve universal HealthCare in UK
    • aggregate services for patients
    • 15 million patients
    • enable two ways communications between patients and care givers via a Personal Health Organizer / PHR called healthspace
      • appointments, calendar, reminders,
      • over the counter medication
      • access to health organizer
      • audit trail for users (who logged etc ...)
  • Alex Savic, CEO Alensa
    • based in switzerland
    • customers in Romenia, Serbia
    • eCmmerce platform for para-pharmacy products (selling drugs online is still illegal in Europe)
    • health blog network is very useful to help monetize their content (premium posts canbe paid by mobile phone).
    • biggest issues are legal issues in europe.
  • Paul Meyer, chairman Voxiva
    • company started 7 years ago
    • provide patients with tips and information on living with a chronic condition
    • e.g. disease surveillance system (Peru 2002)
    • e.g. interactive risk assessment on hearth and cardiac conditions via SMS (Mexico 2007)
    • tools to quickly build applications (e.g. diabetes risk profile population)
  • Josh Nesbit, FrontlineSMS
    • enables users to send and receive text messages with large groups of people through mobile phones.
  • Deb Levine, ISIS
    • non profit organization located in Oakland, CA
    • SMSs for prevention and referral
    • Sexinfo, Realtalk, Data violence prevention etc ...
    • E.g. SMS to 61827 'HIVinfo' or 'Text Meds'
  • Doug Solomon, CTS, IDEO
    • design company (device, software, organization)
    • integrate human, business, technology aspects

Deep Dive: American Well
Demo of the AmericanWell, an online medical care services product:
  • online services for patients and physicians
  • two way conversation (video conference or voice over IP) between doctor and patient
  • patient:
    • agenda, assessment, provider search, message center, health profile and history.
    • integrated with Health Vault
    • ability to rate the service delivered by the doctor
    • forward conversation to the patient PCP
  • doctor:
    • claim submitted automatically
HMSA Online Care:
  • Hawaii - 7,000 members
  • rural country with a large growing senior population
  • uninsured young population

Panel: Tools for ConsumersPersonalized, Analytical, Supporting Decisions, Enabling Transactions
  • Kevin Nolan, CEO ADAM
    • ADAM content using the iphone
  • David Clymer, CEO, MyMedLab
    • purchase test online
    • go to a local lab
    • results are reviewed and put into a PHR
    • available in 47 US states (except RI, NJ, NY)
  • Linda Avey, Co-CEO, 23andMe
    • account can be shared
    • study paternal/maternal Halogroups
    • study health risks (clinical reports, research reports)
    • compare family, friend genes
  • Mari Baker, CEO, Navigenics
    • goal: introduce personalized medecine in HealthCare
    • offers access to a genetic counselor
    • estimated lifetime risks
    • recommendations to reduce health risks
  • Adam Bosworth, CEO, KEAS
    • demo of My Health Plan
      • todo list, overall progress, lab results, meal, exercise action plan
      • import data from google health
      • tracking vital signs and process over time
      • warning about health risks
  • Roy Schoenberg, CEO AmericanWell
    • demo online services for patients and physicians
  • Michael Cho, CEO, Destination Rx
    • 50 millions customers
    • help manage medicine cabinet
    • provides warnings about drug interactions
    • offer ways to lower cost (therapeutic alternatives/generics) including dosage
    • therapeutic alternatives covers 200 tops drugs in the US
  • Erick VonSchweber, CEO, PharmaSurveyor
    • regimen survey tool
    • transferred from partners (Google, Destination Rx ...) using CCR
    • interaction drugs panel
    • ability to replace one drug by another one if there is an elevated risk
  • Alexandra Drane, President, Eliza

Getting Past the Privacy Conundrum

  • Jennifer Gilburg, Verisign
    • demo of VIP : a consumer solution for authentication
    • one time token ID generated by hardware token
    • hosted service
    • SSO usable across different web applications
  • Alan Viars, CEO, Videntity
    • Verification and authentication tools
    • REST based API
    • verification by voice over IP + Pin & voice recognition

Panel: Genomics online * For the patient, there is a benefit knowing in advance the health risks associated to his/her genetic background. This type of information give some type of empowerment to the patient as well.
  • Linda Avey, Co-CEO, 23andMe
    • $399 per genetic analysis study
    • 4-6 weeks for the result
    • 23andWe: sharing information about surveys (phenotype)
  • Tera Eerkes, CEO, QTrait
    • Genetic testing
    • $99 per genetic analysis study
    • dashboard with risk factors
    • technical reports that can be shared with the physician
    • non technical report to share with friends and family
    • specific tests for mate/couple genetic matching to reduce health risks
  • Ilya Kupershmidt, Co-founder, VP of Product Management , NextBio
    • 1/2 million users (researcher, consumers)
    • 60 million pages of resources
    • use public experimental data
    • clinical trials information
    • use ontology to summarize the relevant information data
  • Daniel Reda, Co-Founder, CureTogether
    • demo of CureTogether
    • health tracking tools will be added
    • data to be use for gene discovery
    • twitter for your health

Demo Panel: Disease Management 2.0

  • Stan Nowak, CEO Silverlink, Silverlink
    • recommendation: try to model and automate the routine healthcare activities
    • communication programs for disease management
    • a way to drive behavior (to reduce cost and improve performance of chealthcare).
    • interactive phone calls with health coach
    • educate patients how to save money on drugs
  • Suneel Ratan & Ileana Welte, SVP, Health Hero Network
    • recommendation: keep give supports to your customers to improve the relationship with the patient
    • health body applicance / tele-health platform
    • connect patients and care givers (e.g. institutions)
    • 27,000 customers every day
    • biggest provider to the veteran administration
    • reduce customer care cost by 20%
  • Neal Kaufman, CEO, DPS Health
    • recommendation: try to mimic face to face visits
    • weight management program application
    • internet coach send notes to the patient using past performance
    • integrated with an EMR
    • lessons, workbook, tracking plan, resources and communication tools
    • graphs showing performance
    • send weekly feedback
    • GUI need some refreshing/update (need a modern look and feel) !
  • Don Kemper, CEO, HealthWise
    • recommendation: help each person to help themselves, improve their live and say no to the caregiver when needed!
    • guided self disease management
    • $60 per nurse call
    • for details, send email to moreinfo@healthwise.com

Wednesday, October 22, 2008

Health 2.0 - 2008 (San Francisco) - Day 1

This year, the Health 2.0 2008 conference crowd is definitively larger than last year. I was expecting also a larger exhibition as well, but in fact, the action really seems to take place in the panel discussions and meeting people and peers rather than on the demo booths. However there were some interesting demos during the panel sessions.

The future of Health 2.0 (Indu Subaiya - Matthew Holt)What is the best way to engage people to use Heathcare Apps?

=> A survey provided some interesting information:
  • most frequent channel is conversation
  • social media is much more credible when coupled with Health expertise (e.g. blogs, videosharing, wikipedia).
=> Tools are changing dramatically (Personalized, Analysis, Decision support, transactions)
  • Search Social networks (still the top application), tools, content, Transaction data
  • Health 2.0 Accelerator initiative (To help launch Health 2.0 related ventures).

Keynote : Here Comes Health - Clay Shirky

Clay talked abou this boook:
Here Comes Everybody: The Power of Organizing Without Organizations
  • aggregation is different: a group of patient behave different from single patients
  • add more value (interaction between participants adds synergy
  • information: most of the traffic on the internet is between people, not computers

Documentary: The Great American Health 2.0 Motorcycle TourAn interesting video created by Health 2.0 wher David Kibbe visits (on a motorbike) new Health 2.0 companies and models models throughout the US
Panel: The role of the Consumers Aggregators
  • Wayne Gattinelle, Philip Marshall, WebM
    • presentation of the Verizon HealthZone (branded WebMD web site/application)
    • alert, visit, Conditions, Medications, Allergies, Surgeries, Immunizations, Tests
    • medication advisor: decision support for cost and benefits
  • Michael Yang, Yahoo!
    • collaboration with water front
    • deal with healthgrades
    • presented new visual design for the next generation applications
    • new front door access from Yahoo! Health
    • a profile page describing the physician will be available
    • collaboration with water front media
      deal with healthgrades
  • Roni Zeiger, MD, Product Manager, Google Health & Brad Crosslin, PDX (Google partner)
    • Demo showing integration of Google Health with pharmacies
      • Myer 10 Millions patients
      • Duane Reade (export data into Google Health)
  • Peter Neupert, Health Solution Group, Microsoft
    • partnership with Kaiser (glimpse at the demo)
    • demonstration of PHR (www.myhealthManager.com) 2.5 millions users currently.
    • capabilities to export data into Microsoft HealthVault
    • shows which information is sent to Microsoft (wrapped into a HL7 document)
  • Mark Bertolini, President, Aetna
    • 3rd largest insurance in the US
    • 3200 IT personal
    • cost of care tool
    • partnership with Microsoft (Health Vault)
    • PHR
      • 7 millions users by the end of 2008
      • one million of alerts every 3 months
Panel: Search, UGc and the Long Trail, Matthew Holt & Indu Subaiya- Personalization is very important
  • Venky Harinarayan, Co founder, Kosmix/Right health
      • vertical search engine
      • search results on medical content, community, forums
      • 2nd web site after WebMD
      • aggregate services
  • Well Shell, CEO, HealthLine Networks
    • content provided from 20 partners
    • 70% of the search are related to symptoms
    • learning centers automatically generated
    • drug search including FDA alerts and drugs interaction checker
    • patient decision support as outcome of the search
  • Steven Krein, CEO, Organized Wisdom
    • use a team of medical personal to search Google and hand craft search results
    • long tail search: very specific and personal questions (e.g. side effect of hip surgery) that are answered by organized wisdom.
    • research notes + top resources that are created for aggregated groups of users
    • 20,000 patient cards
    • Organized Wisdom is going to create profiles for every doctors, dentists and practitioners.
  • Tom Eng, President, Healia/Meredith Group
    • vertical search engine: provides high quality trusted results (patent pending algorithm)
    • health communities: locate patients close by and 'ask questions' feature.
  • Daniel Palestrant, Founder and CEO, Sermo
    • millions of questions on their site
    • very interesting study case of allergy form Victoria's secret Bras that was detected by Sermo after studying new group posts.

Demo Panel: Managing Money in Health 2.0* Money starts to play a role in Health 2.0 as transactions start to take more importance.

  • Christopher Parks, CEO, Change HealthCare
    • demo: tool to share, compare and track healthcare expense
    • business models: licensing by employers
    • detailed medical bills
    • summary by family member, by provider, by service date, by health issue
    • average cost per providers for 5 providers in the same area <= nice!
  • Stefanie Fenton, Quicken Health Group, Intuit
    • demo of Quicken Health to be launch in 2009 for UnitedHealthcare, CIGNA HealthCare, and Medical Mutual of Ohio initially
    • business model: pay per transaction + license fees
    • visited more than 300 people to understand their healthcare finance need (the amount of bills/paper tracks can be very large)
    • 3 years of development
    • health plan claims are dowloaded
    • claims to be paids, deductibles with break down on each items how it is reimbursed (as tooltips)
    • payment history with patterns of spending that can be exported for taxe purpose
  • Phil Micali, CEO, Bwell-inc.com
    • demo of bwell informed launched last year (B2B and B2C)
    • business models: licensing by employers
    • include saving accounts, health profile, compare family plans <= very nice!
  • Brandt Cannici, Co-Founder and COO, Medicaresaver.com
    • demo of medicaresaver.com
    • business model: commisions and strategic partneships
    • includes therapeutic interchange proposal and generate letter for doctor <= cool!
    • compare restricted and non-restricted plans
    • focus on seniors
    • no advertizing, HIPAA compliant
Demo Panel: Clinician Social Networks

  • Rex Jabovits, Mypac.net
    • YouTube or Flickr for radiology
    • more than 18,000 cases containing more than 90,000 images
    • Sharing of medical images (flash + ajax)
    • free service funded in part by the National Institutes of Health.
  • Jason Bhan, Co-founder, Ozmosis
    • online Medical Knowledge Exchange
    • accelerates learning and knowledge exchange across medicine
    • journal club, clinical cases, groups etc ...
  • Michael Sands, Co-Founder, MedicalPlexus
    • ecosystem/network in which doctors and life science researchers can connect, interact, and share their work
    • learning from and Sharing Knowledge with other professionals/colleagues using questions and answers
  • Lance Hilll, CEO, Within 3
    • private professional networking site for health and life science practitioners to find, connect and collaborate (the linkedin for medical practitioners)
    • ability to communicate news and event information
    • find colleagues with similar interest by location
    • consultation with specialist on atypical cases, new treatments etc ...
    • offer ways to build communities
    • REST APIs will be available in 2009 to access member data
  • Tobin Arthur, CEO, iMedExchange
    • online community for physicians

See also Day 2 of the conference.



Tuesday, September 30, 2008

The ABCs of Google Health Data API

Recently, I have been involved in a small project to aggregate medications from various Personal Health Records (PHR), including Google Health.

The documentation for the Google Data APIs Client Library and the Health Data API is quite complete and extensive. But it can be also be quite complex for someone who want to develop quickly a prototype or just test a proof of concept using these APIs.

Since I was going to develop my project in Java, I first downloaded he most recent GData Java Client Library (version 1.22 with samples - 6.8 MB).

The sample code can be used out of the box for a simple stand-alone java testing program.

I did import the sample code and the library in my IDE (eclipse) and just changed the credentials (sample.credentials.username and sample.credentials.password) in gdata/java/build-samples/build.properties using my google health account login and password.

To run the Google Health sample program, at the prompt under ./gdata/java just run: ant -f build-samples.xml sample.health.run
The next step for me was to reuse the sample code to develop a web application (I am creating small Liferay JSP based portlets).

Google offers two platforms for the developers to test their applications:
For my small web project I initially tested my code against H9, as recommended by Google.
The main reason is because the authentication with H9 is more simple than with Google Health production.

The application I wanted to build is supposed to connect to various PHRs (ICW LifeSensor, Microsoft Health Vault and Google Health/H9) and retrieve the medication lists. For Google I don't need to enter a login and password in my web application since I am going to use Google AuthSub mechanism:



By clicking on the Google 'connect' button, I am redirected to the Google AuthSub web site:

     <input id="btn_connect_google" name="Disconnect" type="submit"
         value="Connect" onClick="connectToGoogle();return false;"/>

Here is the Javascript function I use for URL redirection:

     function connectToGoogle() { 
       if (btn_connect_google.value == "Connect") {
          window.location.href = googleAuthSubURL.value;
       }
       else {
          btn_connect_google.value = "Connect"; 
       }
     }
I construct the AuthSub URL in advance in my JSP java code:
public String getGoogleAuthSubURL(HttpServletRequest request) {
     
       gh9s = new H9Service("ICW-H9Medications-1.0");

       String nextUrl = "http://localhost:8080/sample/hello.jsp";
       String scope = "https://www.google.com/h9/feeds/";
     
       boolean secure = false;
       boolean session = true;
    
       String authSubLink = AuthSubUtil.getRequestUrl(nextUrl, scope, secure, session);
       authSubLink += "&permission=1";
       authSubLink = authSubLink.replaceFirst("/accounts/AuthSubRequest", "/h9/authsub");
     
      return authSubLink;
   }
I store the URL in an hidden field:

   <input type=hidden id="googleAuthSubURL" value="<%= getGoogleAuthSubURL(request) %>" >

You can refer to the Google Data API and Google Health API, including security settings for AuthSub Request and application identification (for logging purpose).

I am redirected to the Google AuthSub WebSite where I can choose which H9 account I want to use.




Then I am redirected back to my original application, with a single use token associated to the request. I can then parse the request and extract the token that I exchange for the token session:
  http://localhost:8080/sample/hello.jsp?token=1%2FBtOEh.....lsYenOFQ&permission=1
  if (gh9s != null)  {        
      try {
        
         // Extract Single Use Token for the session
         String queryString = request.getQueryString();
                  if (queryString != null) {
           
                      String singleUseToken = AuthSubUtil.getTokenFromReply(queryString);
                 
                      if (singleUseToken != null) {
                        String sessionToken = AuthSubUtil.exchangeForSessionToken(URLDecoder.decode(singleUseToken, "UTF-8"), null);
                        gh9s.setAuthSubToken(sessionToken);
                        System.out.println("Google SetAuthSubToken");
                          
                        URL profile_url = new URL(PROFILE_DEFAULT_PATH);
                        System.out.println("Google ProfileURL:"+profile_url);
                        gh_feed = gh9s.getFeed(profile_url, ProfileFeed.class);
               
                        createReferences(gh_feed.getEntries());
                      }
                  }
            } catch (AuthenticationException e) {
                throw new RuntimeException(e);
            } catch (IOException e) {
                throw new RuntimeException(e);
            } catch (ServiceException e) {
                throw new RuntimeException(e);
            }
        }

For my portlet version (Liferay), I just had to replace the definition of the current URL:
   String singleUseToken = AuthSubUtil.getTokenFromReply(getCurrentURL(request).getQuery());

   private URL getCurrentURL(HttpServletRequest request) {
    try {
       return(new URL(request.getScheme(), request.getServerName(), request.getServerPort(), request.getAttribute("CURRENT_URL").toString())); 
    } catch (MalformedURLException e) {
    throw new RuntimeException(e);
    }
   }
The next step is to obtain medication entries by parsing the Google CCR data feed:

  private void createReferences(List entries) { 
     if (entries != null) {
        for (ProfileEntry entry : entries) {
           System.out.println("Google CCR:"+entry.getContinuityOfCareRecord().getXmlBlob().getBlob());
                 GoogleCCRWrapper ccrWrapper = getDomRepresentation(entry);
                 if (ccrWrapper.containsMedications()) 
                    medication_list.add(ccrWrapper.getMedication());
                    source_list.add(SRC_GOOGLE_HEALTH);
         }
      }
   }

The GoogleCCRWrapper java class parses the CCRg XML data feed:

    public GoogleCCRWrapper(String xml) {
        DocumentBuilder builder = null;
        try {
            builder = documentBuilderFactory.newDocumentBuilder();
        } catch (ParserConfigurationException e) {
            throw new RuntimeException("Error creating DocumentBuilder.", e);
        }
        
        try {
            document = builder.parse(new ByteArrayInputStream(xml.getBytes()));
        } catch (SAXException e) {
            throw new RuntimeException("Error parsing XML.", e);
        } catch (IOException e) {
            throw new RuntimeException("Error parsing XML.", e);
        }
    }
public boolean containsMedications() {
        return document.getElementsByTagName("Medications").getLength() > 0;
    }

    public String getMedication() {   
     Element e = getElementFromDocument("Medications");
     e = getElement(e, "Medication");
     e = getElement(e, "Product"); 
     e = getElement(e, "ProductName");
     e = getElement(e, "Text"); 
     return getText(e);
    }

Here is the resulting portlet (Google Health and Lifesensor Medications):

Friday, August 29, 2008

Liferay Portal : My first impressions



My company ICW creates Health Care web applications and solutions.

We have a need to create reusable components that can be bundled into highly customizable and personalized web applications. Our stack uses Java Enterprise and Web 2.0 technologies, so we naturally turned to the open source Liferay Portal.

This was my first experience with Liferay. By looking at the features, it seems that this portal solution had a lot of things we were looking for:
  • A well recognized open source product (1.5 million downloads, 6000+ registered participants ...)
  • A business-friendly MIT License
  • Compatibility with all major servers, databases and operating systems (we are using Tomcat, Oracle, Windows for development and Linux for production).
  • Compatibility with our stack (J2E) and light container (Spring).
  • An easy way to create new skins and branding
  • An integrated content management system
  • Highly secure platform (especially important for Health Care applications)
Installing Liferay (version 5.1.0) was a little bit longer than expected (>1 GB), but after this, it went pretty smoothly besides minor MySQL configuration issues. This installation included all the source code of Liferay (I did not have to customize the code initially, but it seems nice to have all the source code available in case ...).

I did create a specific project for our need - a portal version of our Personal Health Record (PHR) - call phr-portal-assembly (see screen shot on the left):

I liked the fact that the runtime portion of the portal is contained inside the project: bundles/tomcat/ (although this takes a lot of space if you have several projects).

To be up and running, you just have to start MySQL and Tomcat and open a browser at http://localhost:8080/web/guest/home (I am using Firefox).

I find it easy to create new plugins (portlets and themes). You just have to open a prompt under the liferay-plugins-sdk-5.1.0/portlets or liferay-plugins-sdk-5.1.0/themes directory and use the command:

create new_portlet_name new_portlet_title and
create new_theme_name new_theme_title

I was then able to start to modify my portlet skeletons (by modifying the default view.JSP file under docroot) and redeploy them (without having to restart tomcat!) by using the ant deploy command. Easy and efficient!

For the themes, I was a little bit different: The style sheet changes/differences is specified under the docroot/_diffs and the new theme is built by adding the differences to the default classic look and feel.

Becoming familiar with the portal application itself was not too complicated. Especially with version 5.1.0 which can give admin rights to any type of users, so I was able to customize my portal page without having to log a as an administrator.

To make the border/chrome disappear, I just had to click on the look-and-feel icon.








This opens a new window where I had to uncheck 'Show Borders' and refresh the browser.






After this, I had to uncheck the 'Toggle Edit Controls' check box.

The resulting portal had the same look and feel as our initial PHR, but was now highly customizable.I did some also some quick tests with different layouts and themes that was provided by one of my colleague with fast and good and results. We also did some tests encapsulating an existing Flex based application and some widgets with great success.

Overall my first impression of Liferay portal is a very positive one.

I am now looking forward to tackle the re-factoring of our existing products with this technology (we are using JSF, Ajax and Flex as front-end technology)!