A Mobile Application for My Dog
R. Alexander Milowski
milowski at sims.berkeley.edu
#1
That Mobile Application...
He's still pouting.
He still wants to go the beach.
#2
Web Browsers & Phones
If you've bought a cell phone in the last year or two, you are likely to have a web browser on your phone.
Most likely that web browser will display XHTML only.
If you've got the right services on your plan, you can surf an XHTML website on your phone.
Some mobile browsers will even do CSS.
#3
Tide Information for Hudson
All we need to do is build a web application that:
Gets the tide information for today.
Calculate if "right now" is close to low tide.
Display some kind of XHTML document that is appropriate for a cell phone web browser.
The results just have to be served as XHTML's content type: application/xhtml+xml
Otherwise, you can't view the page.
#4
Technology Choices - Web Application
We could write the web application as JSP pages or as a servlet.
We'll have to possibly filter the data that comes back.
Maybe XSLT would be helpful.
We have to:
Format a request.
Send it to the service.
Parse the response.
Compare the times to the current time.
Format the response for the cell phone.
An XML Pipeline would be very helpful here as well.
#5
Design Constraints
Links are better than typing for obvious reasons (e.g. no keyboard).
Forms work but typing information is a problem.
I only go to a handful of beaches, so I don't want every beach location in the US to show up on my phone.
The result needs to be easy to see as the screens can be hard to read in the sunlight.
In fact, I really want to be able to just glance at the phone and "know".
#6
Design Concept
I'll pre-author locations from my desktop that I'll use to populate the location choices.
Each location will end up being a link in the web application for easy navigation.
The result will have:
A green box for low tide.
A yellow box for within an hour of low tide.
A red box otherwise.
The low and high tides should be displayed as well.
#7
A Simple Idea
Why not make each location just a link?
When the link is accessed, it contains the information for what location to get tide information.
Maybe something like:
<a href="tides/9414290">San Francisco, CA</a>
Each URL context/tides/nnnnnnn will get the tide information for the location number as specified by 'nnnnnnn'.
#8
Getting Started
We'll make a web application project in Netbeans.
We'll make an 'index.xhtml' document with a set of links to locations we'd like to have on the cell phone:
<html xmlns="http://www.w3.org/1999/xhtml"> <head><title>Tide Info</title></head> <body> <p><a href="tides/9414290">San Francisco, CA</a></p> <p><a href="tides/9413450">Monterey, CA</a></p> <p><a href="tides/9410660">Los Angeles, CA</a></p> <p><a href="tides/9410170">San Diego, CA</a></p> </body> </html>
That web page should be authored for the cell phone's display size.
#9
The urlrewrite Component
The urlrewrite component's urlrewrite.xml can map the 'tides/nnnnnnn' URL to a pipeline:
<rule> <condition type="method">GET</condition> <from>^/tides/(.+)</from> <to>/request.pd?location=$1</to> </rule>
And we'll change the web.xml to invoke that component:
<filter> <filter-name>UrlRewriteFilter</filter-name> <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class> <init-param> <param-name>confReloadCheckInterval</param-name> <param-value>60</param-value> </init-param> </filter> <filter-mapping> <filter-name>UrlRewriteFilter</filter-name> <url-pattern>/*</url-pattern> <dispatcher>REQUEST</dispatcher> <dispatcher>FORWARD</dispatcher> </filter-mapping>
Keep in mind you need to copy the supporting jar files into 'WEB-INF/lib'.
#10
Setting up the Pipeline Engine
Configure the web.xml to run pipelines for .pd files:
<servlet> <servlet-name>PipelineEngine</servlet-name> <servlet-class>com.smallx.servlet.PipelineServlet</servlet-class> <init-param> <param-name>check-for-changes</param-name> <param-value>true</param-value> </init-param> <init-param> <param-name>default-pipeline</param-name> <param-value>request.pd</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>PipelineEngine</servlet-name> <url-pattern>*.pd</url-pattern> </servlet-mapping>
This pipeline will be used for get requests and so we don't need to create an 'index.xml'.
#11
Pipelines and Query Parameters
If the request URL contains query parameters, those parameters get converted into XML.
That XML is the input to the pipeline.
In our case, we get:
<f:form xmlns:f="urn:publicid:IDN+smallx.com:server:forms:post:1.0"> <f:parameter name="location">9414290</f:parameter> </f:form>
#12
Creating the Pipeline
We mapped the tide/nnnnnnn requests to request.pd?location=nnnnnnn as so we need to create that pipeline.
The first step is to turn our parameter into a request to the web service:
<p:pipe xmlns:p="urn:publicid:IDN+smallx.com:pipeline:1.0" name="changeme" xmlns:c="urn:publicid:IDN+smallx.com:component-language:1.0" xmlns:f="urn:publicid:IDN+smallx.com:server:forms:post:1.0" xmlns:param="urn:publicid:IDN+smallx.com:server:parameters" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:t="http://www.smallx.com/services/tideinfo/2005" > <p:template> <xsl:param name="param:server"/> <c:url-post href="{$param:server}tideinfo-service/tideinfo.pd"> <t:tideinfo location="{/f:form/f:parameter[@name='location']}"/> </c:url-post> </p:template> </p:pipe>
We now have to embed a URL to the web service somehow. In this case, the application assumes it is on the same web server.
#13
Calling the Web Service
We now just add the [p:]url step to the pipeline to call the web service:
<p:pipe xmlns:p="urn:publicid:IDN+smallx.com:pipeline:1.0" name="changeme" xmlns:c="urn:publicid:IDN+smallx.com:component-language:1.0" xmlns:f="urn:publicid:IDN+smallx.com:server:forms:post:1.0" xmlns:param="urn:publicid:IDN+smallx.com:server:parameters" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:t="http://www.smallx.com/services/tideinfo/2005" > <p:template> <xsl:param name="param:server"/> <c:url-post href="{$param:server}tideinfo-service/tideinfo.pd"> <t:tideinfo location="{/f:form/f:parameter[@name='location']}"/> </c:url-post> </p:template> <p:url/> </p:pipe>
The result of this pipeline is the tide information.
#14
Styling the Result
Adding an XSLT step at the end allows the content to be styled for the mobile browser:
<p:pipe xmlns:p="urn:publicid:IDN+smallx.com:pipeline:1.0" name="changeme" xmlns:c="urn:publicid:IDN+smallx.com:component-language:1.0" xmlns:f="urn:publicid:IDN+smallx.com:server:forms:post:1.0" xmlns:param="urn:publicid:IDN+smallx.com:server:parameters" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:t="http://www.smallx.com/services/tideinfo/2005" > <p:template> <xsl:param name="param:server"/> <c:url-post href="{$param:server}tideinfo-service/tideinfo.pd"> <t:tideinfo location="{/f:form/f:parameter[@name='location']}"/> </c:url-post> </p:template> <p:url/> <p:xslt src="mobile.xsl"/> </p:pipe>
The result of this pipeline is XHTML, so we should configure the pipeline engine to set the content type.
#15
The XSLT
This template is really all we need:
<xsl:template match="t:tideinfo"> <html> <head> <title>Tide Info</title> <link rel="stylesheet" type="text/css" href="site.css"/> </head> <body> <xsl:variable name="time" select="date:time()"/> <p class="title"><xsl:value-of select="@today"/> at <xsl:value-of select="$time"/></p> <div> <xsl:variable name="current" select="number(substring-before($time,':'))"/> <xsl:variable name="low" select="number(substring-before(@low-at,':'))"/> <xsl:choose> <xsl:when test="($current - $low)=0"> <xsl:attribute name="class">green</xsl:attribute> <p>Hudson, beach OK!</p> </xsl:when> <xsl:when test="($current - $low)=1"> <xsl:attribute name="class">yellow</xsl:attribute> <p>Hudson, MAYBE.</p> </xsl:when> <xsl:when test="($current - $low)= -1"> <xsl:attribute name="class">yellow</xsl:attribute> <p>Hudson, MAYBE.</p> </xsl:when> <xsl:otherwise> <xsl:attribute name="class">red</xsl:attribute> <p>Hudson, NO beach</p> </xsl:otherwise> </xsl:choose> </div> <p>Low: <xsl:value-of select="substring-before(@low-at,'-')"/></p> <p>High: <xsl:value-of select="substring-before(@high-at,'-')"/></p> </body> </html> </xsl:template>
Note how we use the current time in the stylesheet to control the display of red, yellow, or green boxes.
We really need to add durations to get this absolutely correct but that extension function isn't available in this implementation.
#16
Setting the XHTML Content Type
The simplest way is to add this parameter to the PipelineEngine servlet:
<init-param> <param-name>content-type</param-name> <param-value>application/xhtml+xml</param-value> </init-param>
Keep in mind this will not display in Internet Explorer as it doesn't understand XHTML.
Firefox, Netscape, etc. can display XHTML just fine.
#17
The Working Application
You can try it on your cell phone or desktop: http://www.smallx.com/tideinfo/
Or go to the beach and see if it actually works.
Which Hudson and I did on 04/06/2005 (yesterday) at 16:30 for low tide.
#18
The Cliffs
#19
The Beach from the Top of the Cliff
#20
Hudson is Ready to Go!
#21
Due to technical difficulties...
err...
So I get to the beach...
And the battery dies on my digital camera...
And the cell phone (which has a camera) is in the car up the cliff...
Hudson is running around like a crazy man...
...and the tide is low.
If you don't believe me, try it out yourself with my web application and your cell phone!!!
So much for mobile this and digital that!
#22
A Satisfied Customer
Hudson really doesn't care that you don't believe he went to the beach.
He knows he did.