Skip to content

onebusaway sms webapp

Landon Reed edited this page May 6, 2015 · 3 revisions

The onebusaway-sms-webapp module provides the SMS interface, with support for the Textmarks SMS service. Textmarks is a free, ad-supported SMS shortcode service that allows you to return dynamic responses to incoming keyword-prefixed text messages. See http://onebusaway.org/where/sms.html for more info on using the OneBusAway SMS service.

The Textmark service works by taking an incoming text message like:

onebus #bookmarks add

and mapping it to a HTTP request:

http://localhost:8080/onebusaway-sms-webapp/sms/textmarks.action?phoneNumber=12065551234&message=%23bookmarks%20add

The body of the HTML in the response will be sent back to the user as an SMS response. Thus, generating SMS responses isn't much different than generating a webpage, so we use many of the same technologies that we use in the regular onebusaway-webapp, including Java servlets, Apache Struts, and JSPs.

Action Hierarchy

Even though we support a variety of SMS responses depending on the request sent by the user, all incoming messages all map to the same incoming URL and the same corresponding Struts action:

org.onebusaway.sms.actions.TextmarksAction

To keep from having the !TextmarksAction become overly complex, we use a lot of action-chaining to redirect to other actions to handle response generation. For example, if the incoming sms message starts with a "#" character, we treat it as a command and chain our response to the "command" result and corresponding:

org.onebusaway.sms.actions.CommandAction

All the actions defined in the org.onebusaway.sms.actions package are reachable from the main textmarks action entry point through this chaining redirection mechanism.

A Note on Sessions

One piece of standard Java servlet container technologies that we can't rely on is sessions. Specifically, the Textmarks service ignores all cookies, including JSESSIONID, and make no attempts to make sure that repeated requests coming from the same phone number are mapped to the same session.

Instead, we take on the task of mapping repeated requests by the same phone number to the same session on our own. Check out:

org.onebusaway.sms.impl.TextmarksSessionInterceptor

It's an XWork / Struts interceptor that maps the phone number parameter to a persistent session map and replaces the default XWork / Struts !ActionContext session with the session for the phone number.

Running the Webapp

To run the sms webapp, you need to follow a couple of steps:

  1. Check out the source into Eclipse: ImportingTheSourceIntoEclipse
  2. Setup a server instance to run the onebusaway-sms-webapp module: [SettingUpATomcatServerInEclipse] a. Be sure to add the onebusaway-sms-webapp project to the server you setup
  3. Configure appropriate data sources for the webapp: [#Configuring_Data_Sources_for_the_Webapp Configuring Data Sources...]
  4. Start the server and check for exceptions
  5. Browse to the results at http://localhost:8080/onebusaway-sms-webapp/sms/textmarks.action?phoneNumber=2065551234&message=%23help

Configuring Data Sources for the SMS Webapp

The sms webapp module won't just run out of the box. You need to configure the various data sources it will use to retrieve transit data, user data, and other configuration information.

Because this configuration information is typically specific to each developer, many of the files controlling configuration are not included in the source tree. However, default files that should serve as a good starting point can be found in

onebusaway-sms-webapp/src/main/default-resources

data-sources.xml

The bulk of configuration is performed in the file:

onebusaway-sms-webapp/src/main/resources/data-sources.xml

Again, by default, this file is not actually included in the source tree. We do, however, provide a default starting point in onebusaway-sms-webapp/src/main/default-resources/data-sources.xml. Simply copy the data-sources.xml file into src/main/resources and begin editing. We'll walk through the sections in that default file, describing what they are up to.

First, we specify out transit data source (more details at TransitDataServiceConfiguration):

<bean id="transitDataService" class="org.springframework.remoting.caucho.HessianProxyFactoryBean">
    <property name="serviceUrl" value="http://soak-transit-data.onebusaway.org/puget_sound/remoting/transit-data-service" />
    <property name="serviceInterface" value="org.onebusaway.transit_data.services.TransitDataService" />
</bean>

Next, we specify a database data source that will be used by various components (user profiles, etc):

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="org.hsqldb.jdbcDriver" />
    <property name="url" value="jdbc:hsqldb:file:/tmp/org_onebusaway_database" />
    <property name="username" value="sa" />
    <property name="password" value="" />
</bean>

By default, we specify an in-process HSQLDB, because it's the easiest to setup. However, this convenience comes with a loss of flexibility (can't connect to the db with command-line tools, can't share the db between multiple processes), so feel free to switch the datasource to something different (a stand-alone HSQLDB instance, a MySQL database, your favorite database...). Note that you'll need to update the hibernate.dialect property to match the Hibernate dialect appropriate for your data source.

The next entry sets up a geocoder used by the SMS interface. The default geocoder implementation has VERY limited functionality, but is sufficient for testing.

<bean id="externalGeocoderImpl" class="org.onebusaway.geocoder.impl.DefaultGeocoderImpl" />

The final entry specifies a default search location object:

<bean id="serviceArea" class="org.onebusaway.presentation.impl.DefaultServiceAreaServiceImpl" />

The next entry specifies SMS name abbreviations. Note that it references an sms-destination-abbreviations.xml file on the classpath. Like data-sources.xml, that file is not included by default. See details about this file in the next section.

<bean id="smsAbbreviationsFactory" class="org.onebusaway.presentation.impl.text.XmlTextModificationsFactory">
  <property name="resource" value="classpath:sms-destination-abbreviations.xml" />
</bean>

<bean id="smsAbbreviations" factory-bean="smsAbbreviationsFactory" factory-method="create">
  <qualifier value="smsDestinationAbbreviations" />
</bean>

The final entry specifies a default search location object:

<bean id="serviceArea" class="org.onebusaway.presentation.impl.DefaultServiceAreaServiceImpl" />

sms-destination-abbreviations.xml

In the data-sources.xml file, we specified an sms-destination-abbreviations.xml file on the classpath that defines SMS place name abbreviations. We include a default file that you can use. The format of the file is pretty simple:

<?xml version="1.0" encoding="UTF-8"?>
<text-modifications>
  <replacement from="Ballard - Adams" to="Ballard" />
  <replacement from="Ballard - Loyal Heights" to="Ballard" />
  <replacement from="Ballard - Sunset Hill" to="Ballard" />
  <replacement from="Beacon Hill - South Beacon Hill" to="BeaconHill" />
  <replacement from="Belltown" to="Belltown" />
  <replacement from="Bitter Lake" to="BitterLk" />
  <replacement from="Black Diamond" to="BlckDmnd" />
  ...
</text-modifications>