MyHealth — Adding People

Before Thanksgiving, we created the model that lets us represent people in MyHealth. Now let’s add some people, particularly my family, because that’s what I’m building MyHealth for in the first place.

First, we’ll replace the front Viewlet with one that shows a list of people whose data is being managed. So we open up MainViewletFactory.java and make its determineFactoryChoicesIgnoringType method look like this:

public ViewletFactoryChoice [] determineFactoryChoicesIgnoringType(
        MeshObjectsToView toView )
{
    JeeMeshObjectsToView realToView = (JeeMeshObjectsToView) toView;

    ArrayList<ViewletFactoryChoice> ret = new ArrayList<ViewletFactoryChoice>();

    MeshObject subject = toView.getSubject();
    if( subject.getMeshBase().getHomeObject() == subject ) {
        ret.add( DefaultJspViewlet.choice( realToView, "org.infogrid.myhealth.viewlet.patients.PatientsCollectionViewlet", ViewletFactoryChoice.PERFECT_MATCH_QUALITY ));
        ret.add( AllMeshObjectsViewlet.choice( realToView, ViewletFactoryChoice.GOOD_MATCH_QUALITY ));
        ret.add( AllMeshTypesViewlet.choice(   realToView, ViewletFactoryChoice.AVERAGE_MATCH_QUALITY ));
    }
    ret.add( DefaultJspViewlet.choice( realToView, "org.infogrid.jee.viewlet.propertysheet.PropertySheetViewlet", ViewletFactoryChoice.AVERAGE_MATCH_QUALITY ));
    return ArrayHelper.copyIntoNewArray( ret, ViewletFactoryChoice.class );
}

This means that preferably, the app’s front page is now going to be run by a Viewlet called org.infogrid.myhealth.viewlet.patients.PatientsCollectionViewlet. Which we’ll create by creating

  • a JSP file called PatientsCollectionViewlet.jsp at location web/v/org/infogrid/myhealth/viewlet/patients/. For now, just put in a placeholder HTML content.
  • a corresponding CSS file at web/v/org/infogrid/myhealth/viewlet/patients/PatientsCollectionViewlet.css.
  • A property file that contains the name of the viewlet, at java/org/infogrid/myhealth/viewlet/patients/PatientsCollectionViewlet.properties.

(You can find their content in SVN).

Finally, we use the InfoGrid JSPO mechanism (“Java Server Pages Overlay”) to quickly add an editable GUI. The essence of that is this code in the JSP:

    <u:callJspo page="/o/personcollection/create-patient.jspo" action="${Viewlet.postUrl}" linkTitle="Create a new patient" submitLabel="Create">
     <img src="${CONTEXT}/s/images/add.png" alt="[add]" />
    </u:callJspo>

This includes a JSP fragment with the overlay dialog, which looks like this:

<h2>Create patient</h2>
<input name="shell.patientcollection.access" type="hidden" value="find" />
<input name="shell.patientcollection" type="hidden" value="users" />
<input name="shell.patientcollection.to.patient.perform" type="hidden" value="relateifneeded" />
<input name="shell.patientcollection.to.patient.blessRole" type="hidden" value="org.infogrid.model.MyHealth/PersonCollection_Collects_Person-S" />
<input name="shell.patient.access" type="hidden" value="create" />
<input name="shell.patient.bless" type="hidden" value="org.infogrid.model.MyHealth/Person" />
<table class="form" border="0">
<tbody>
<tr>
<th class="label">At URL:</th>
<td>
<input class="identifier" name="shell.patient" size="32" value="users/" /></td>
</tr>
<tr>
<th class="label">First name:</th>
<td></td>
</tr>
<tr>
<th class="label">Last name:</th>
<td></td>
</tr>
</tbody></table>

This uses the HTTP Shell to create a new MeshObject of type Person, which is related to the PersonCollection of users we created earlier, using RelationshipType PersonCollection_Collects_Person. Note that the .jspo file type needs to be declared as JSP file type in the app’s web.xml file.

A few additions to CSS and Javascript (again found in SVN), and we recompile and run.

Now we can add users to the app. Check it out!

MyHealth — Modeling the People

MyHealth is supposed to be for individuals and their families. So we need a way to distinguish whose data is whose. To do that, we create a (very simple) model:

In the model project (org.infogrid.model.MyHealth), we open model.xml and add two EntityTypes and a RelationshipType:

  • Person — represents a person, such as myself, or perhaps later also doctors. For now, it only has FirstName and LastName properties
  • PersonCollection — a collection of people. These collection objects turn out to be rather useful when representing information as a graph, as we do with InfoGrid
  • PersonCollection_Collects_Person — lets us collect Persons in PersonCollections. We make the multiplicity 0:N/0:N to enable the same person to be part of multiple collections. Not sure we’ll need that later but it won’t hurt,.

Then, compile in NetBeans. This automatically runs the InfoGrid code generator, which generates Java interfaces and classes for Person and PersonCollection etc.

Back to the web project org.infogrid.myhealth.www. So far, we hadn’t added a dependency to the model project, which is of course needed so that the web app can use the model we just created. This means we need to add the dependency in the NetBeans project property dialog, and also in the project’s module.adv file.

NetBeans has the unfortunate habit of sometimes getting confused about directory paths; a quick check to project.properties to make sure that hasn’t happened.

Now we’d always like to have an instance of PersonCollection around that acts as the directory of people managed by MyHealth. One good way of doing this is to pick a fixed identifier (say “users”) for the PersonCollection, and to instantiate it when the app starts.

To do that, we open class AppInitializationFilter in the web project, and override method populateMeshBase, which exists for that purpose. In that method, we do this:

mb.executeAsap( new TransactionAction<Void>() {
    public Void execute() throws Throwable {
        MeshObjectIdentifier userCollectionId = idFact.fromExternalForm( "users" );
        MeshObject           userCollection   = mb.accessLocally( userCollectionId );

        if( userCollection == null ) {
            life.createMeshObject( userCollectionId, MyHealthSubjectArea.PERSONCOLLECTION );
        }
        return null;
    }
} );

In other words, if it does not exist yet, we create a MeshObject of type PersonCollection (the type we defined above) with identifier “users”.

Time to compile and run.

Now the MeshBase contains two MeshObjects: the default home object, and the object of type PersonCollection that we just defined at identifier “users”.

Good enough for today; next time, we’ll create some HTML that allows us to create and edit users. As usual, you find today’s code in SVN at http://svn.infogrid.org/infogrid/trunk/ig-app-myhealth.

MyHealth: the Basic Layout

In the first installment, we created an executable, but feature-less application scaffold for MyHealth. Now we’ll modify the basic layout for the app so we can add features in the right places next.

This is easiest if we first run MyHealth under Tomcat right from NetBeans: It still uses the layout from MeshWorld, and says “Unnamed App”. To change that:

  • we open the JSP template that controls the main layout of the app, which is at web/s/templates/default/text/html/template.jsp. As one can tell easily from this path, InfoGrid also supports non-default templates with file formats other than text/html, but for now, we won’t use those features.
  • let’s remove the big InfoGrid icon to the right; built on InfoGrid at the bottom is good enough
  • the app’s main icon to the left needs replacing, so I just whip something up real quick in Inkscape, save it to web/s/images/myhealth.png and change the path in the template file
  • we can leave the footer for now; I don’t know yet whether we’ll use the famfamfam.com icons again or not, let’s leave them in for the time being.
  • now for the CSS, remove some of the lines in color.css and adjust some CSS elements in layout.css

That’s all for today. Code in SVN as usual.

Developing MyHealth on InfoGrid — Day 1

This is the first of a series of posts documenting the creation of an open-source web app called MyHealth to manage personal health and wellness data, based on the InfoGrid Web Graph Database.

This scratches a personal itch, and I figure I might as well chronicle the progress of this little side project so developers new to InfoGrid get a taste.

I don’t think I’m the only geek who’d like to manage their health, wellness and fitness information better and keep it under their own control, so perhaps you might want to help out. There seems to be little or no open-source software for personal health information management that was written in this century, or so, and it will be cool to do it based on cutting-edge NoSQL graph database technology.

I’ll check today’s code every day and post on this blog. As it is a side project, I don’t expect to do more than an hour of work each day, and likely less. You are very welcome to contribute if you like, just send a note to the InfoGrid mailing list.

So here is day 1:

1. Let’s get the InfoGrid code:

mkdir -p ~/svn/svn.infogrid.org/infogrid
svn checkout http://svn.infogrid.org/infogrid/trunk

2. Make sure our setup is right and InfoGrid builds

cd ~/svn/svn.infogrid.org/infogrid/trunk
ig-tools/build.sh -a

This takes a while, so off to writing some of this blog post.

Oops, test failed because I forgot to start Tomcat. So let’s run NetBeans, which I’ll use as my IDE, and run Tomcat from there. Then re-run the last of the user interface tests that depend on Tomcat:

ig-tools/build.sh -run ig-ui

3. We’ll going to put MyHealth right into the InfoGrid SVN:

mkdir ig-app-myhealth
mkdir ig-app-myhealth/modules
mkdir ig-app-myhealth/app

I learned this past week that this directory structure is best described as an “InfoGrid-ism” (Hi Ben!) i.e. a convention that makes using InfoGrid easier. The modules subdirectory will contain the modules from which MyHealth is assembled, other than the InfoGrid modules, and the app directory will contain the web app project.

4. Use the brand-new project creation scripts:

cd ig-app-myhealth/modules
../../ig-tools/create-model-module.pl --name org.infogrid.model.MyHealth \
    --infogridpath ../..

This created a ModelModule, aka a schema for the graph database. Which also can be opened up as a project in NetBeans.

Then we also create a web project by cloning the MeshWorld example app:

cd ../app
../../ig-tools/clone-meshworld.pl --name org.infogrid.myhealth.www \
    --infogridpath ../..

5. Open both of those projects in NetBeans to make sure everything is right and can be built.

Select “Clean and Build” first on the model project, then on the web project. Works fine. We haven’t told those project about each other, but we will later.

6. Setting up a MySQL database.

In MySql, create a database and set some privileges:

mysql -u root -p
mysql> create database myhealth;
mysql> grant all privileges on myhealth.* to 'myhealth'@'localhost' identified by 'secret';
mysql> flush privileges;

In the org.infogrid.myhealth.www project in NetBeans, edit the context.xml file to read as follows:

<?xml version="1.0" encoding="UTF-8"?>
<Context path="/org.infogrid.myhealth.www" cookies="false">
  <Resource auth="Container"
            type="javax.sql.DataSource"
            driverClassName="com.mysql.jdbc.Driver"
            name="jdbc/org.infogrid.myhealth.www"
            url="jdbc:mysql://localhost:3306/myhealth"
            username="myhealth"
            password="secret"
            maxActive="20"
            maxIdle="10"
            maxWait="-1" />
</Context>

To stay on the safe side, rebuild the web project.

6. Assigning an App Server and Run

In NetBeans, open the properties for project org.infogrid.myhealth.www, select the Run tab, and pick a local Tomcat installation as the assigned app server.

Running the web project. It runs! It is totally and utterly useless so far, and has no health content or health-relevant schema of any kind. But it runs, and we’ll keep the MyHealth app running from now on regardless how many changes we make and features we write.

7. Check-in so you guys can check out what has been created so far:

cd ../..
svn add -N ig-app-myhealth ig-app-myhealth/modules ig-app-myhealth/app
ig-tools/add-project-to-svn.pl ig-app-myhealth-modules/org.infogrid.model.MyHealth
ig-tools/add-project-to-svn.pl ig-app-myhealth-app/org.infogrid.myhealth.www

(These Perl scripts are just wrappers around svn to to check the right files and directories of NetBeans projects into SVN)

Done for today. We have a working app even if it does not do anything useful yet.

And, as JP is fond to say, “so to bed”.