[onebusaway] r5496 committed - Edited wiki page AnExampleWebPageRequest through web user interface.

0 views
Skip to first unread message

onebu...@googlecode.com

unread,
Feb 19, 2012, 11:50:16 AM2/19/12
to onebusawa...@googlegroups.com
Revision: 5496
Author: bdfe...@onebusaway.org
Date: Sun Feb 19 08:50:00 2012
Log: Edited wiki page AnExampleWebPageRequest through web user
interface.
http://code.google.com/p/onebusaway/source/detail?r=5496

Modified:
/wiki/AnExampleWebPageRequest.wiki

=======================================
--- /wiki/AnExampleWebPageRequest.wiki Fri Jul 30 17:15:16 2010
+++ /wiki/AnExampleWebPageRequest.wiki Sun Feb 19 08:50:00 2012
@@ -1,221 +1,2 @@
-#summary In-depth details of how a typical web request is processed by
OneBusAway
-#labels Tutorials,GettingStarted,Architecture
-
-<wiki:toc />
-
-The technology stack for OneBusAway is pretty deep. Here we describe a
typical web request from start to finish, touching on all the different
pieces of the response pipeline.
-
-Consider the following request:
-
-http://onebusaway.org/where/standard/stop.action?id=25140
-
-This is the standard arrival page for stop # 25140.
-
-= The Servlet Container =
-
-When a request comes in, a Tomcat servlet container receives the request.
The [ModuleWebapp onebusaway-webapp] module has all the code that power the
web interface for OneBusAway, including the code for setting up our
webapp. Our webapp is specifically configured with the standard web.xml
file located at
-
-{{{
-src/main/webapp/WEB-INF/web.xml
-}}}
-
-
-= Struts =
-
-The next step of the pipeline is [http://struts.apache.org/2.x/ Apache
Struts 2.x], a web MVC framework. A filter is setup in the `web.xml` file
to pass every incoming request to Struts:
-
-{{{
-<filter>
- <filter-name>action2</filter-name>
-
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
-</filter>
-<filter-mapping>
- <filter-name>action2</filter-name>
- <url-pattern>/*</url-pattern>
-</filter-mapping>
-}}}
-
-The Struts action handling code takes over at this point. Struts actions
are configured in the following file:
-
-{{{
-src/main/java/struts.xml
-}}}
-
-The `struts.xml` file is the MVC glue. Specifically, it maps incoming
HTTP requests to Java classes (called Actions in Struts) that will service
the request and then maps the response to a rendering component (JSP in our
case).
-
-Historically, Struts actions each had to be mapped directly in the
`struts.xml` file, which can become quite tedious to maintain for large
projects. Instead, we are using the
[http://struts.apache.org/2.1.6/docs/convention-plugin.html Struts
Convention plugin], which uses Java @annotations to configure action
classes in place. Actions are automatically scanned on the classpath with
the following configuration option:
-
-{{{
-<constant name="struts.convention.package.locators.basePackage"
value="org.onebusaway.webapp.actions" />
-}}}
-
-If we browse to the `org.onebusaway.webapp.actions`, we see all the Action
classes for the OneBusAway webapp, including
`org.onebusaway.webapp.actions.where.StopAction`, the action that handles
the stop request.
-
-= The Action Handler Class =
-
-If we go examine the class, we'll see it's just a simple Java bean with
getters and setters and one entry point method:
-
-{{{
-public String execute() { ... }
-}}}
-
-The execute method is the Action entry point and it's called automatically
by Struts. Before it does, however, Struts automatically maps any request
parameters of the URL to properties of the Action bean. Thus, the
`id=25140` request parameter gets mapped to the `public void
setId(List<Integer> ids)` setter.
-
-
-= The Spring IOC Container =
-
-Note that in addition to bean properties automatically populated by Struts
from the URL, there are also bean properites automatically setup by Struts
and its integration with the
[http://static.springframework.org/spring/docs/2.5.x/reference/index.html
Spring framework]. Spring is an Inversion Of Control (IOC) container that
connects together much of the business logic in OneBusAway. Consider:
-
-{{{
- @Autowired
- public void setTransitDataService(TransitDataService service) {
- _service = service;
- }
-}}}
-
-The `@Autowired` annotation tells Spring that it should automatically
supply the appropriate services classes to the bean. In this case, that
would be the `TransitDataService` service class, which is the main entry
point into business logic from the web control layer.
-
-At this point, once the Action bean has been properly initialized, the
`execute` method is finally run. The `execute` method make a call to the
`TransitDataService` to retrieve the StopsWithArrivalsBean bean, which
includes information about the requested stop plus all the predicted
arrivals at that stop.
-
-{{{
- _result = _service.getStopsWithArrivalsAndDepartures(ids, new Date());
-}}}
-
-= !TransitDataService and !FederatedService =
-
-The `org.onebusaway.transit_data.services.TransitDataService`, defined in
the [ModuleTransitData onebusaway-transit-data] module, hides most of the
implementation detail of collecting actual stop and arrival information,
allowing a clean separation between the UI layer and the data layer. The
separation is so complete that the implementing class for the
`TransitDataService` might actually be running on another server!
-
-When a class is made to `TransitDataService`, a local proxy actually
handles the request. That proxy is typically an instance of
`org.onebusaway.federations.FederatedService`, defined in the
[ModuleFederations onebusaway-federations] module. A `FederatedService` is
once that can look at the arguments on an incoming method call and route
them to an appropriate handler on a local or even remote machine. In our
case, we break transit data up into distinct geographic regions (Puget
Sound vs Portland, for example) and have a `TransitDataService` handler for
each. The `FederatedService` proxy looks as the method arguments (lat-lon
coordinates, agency ids, etc) to decide which `TransitDataService` is best
equipped to service the response.
-
-For method calls across JVMs and machines, we use
[http://hessian.caucho.com/ Hessian] as our RPC serialization method. For
details on how a `TransitDataService` is exported using Hessian, check out
the [ModuleTransitDataFederationWebapp
onebusaway-transit-data-federation-webapp] module.
-
-= !TransitDataFederation =
-
-The actual implementation for `TransitDataService` that does the heavy
lifting of processing a request can be found in the
[ModuleTransitDataFederation onebusaway-transit-data-federation] module.
Specifically, the
`org.onebusaway.transit_data_federation.impl.federated.TransitDataServiceImpl`
is the implementing class.
-
-Here things get pretty complex, as the
`onebusaway-transit-data-federation` defines a lot of service interfaces
and implementations that handle the bulk of the business logic in the
module. Generating the response to the
`getStopsWithArrivalsAndDepartures(...)` call involves calls to a number of
services:
-
- *
`StopWithArrivalsAndDeparturesBeanService.getArrivalsAndDeparturesForStopIds(...)`
- * `StopBeanService.getStopForId(...)`
- * `GtfsRelationalDao.getStopForId(...)`
- * `RouteBeanService.getRouteForId(...)`
- *
`ArrivalsAndDeparturesBeanService.getArrivalsAndDeparturesByStopId(...)`
- * `StopTimeService.getStopTimeInstancesInTimeRange.(...)`
- * `TripPlannerGraph.getStopEntryForId(...)`
- * `CalendarService.getServiceDatesWithinRange(...)`
- * `StopTimePredictionService.applyPredictions(...)`
- * `NearbyStopsBeanService.getNearbyStops(...)`
- * `GeospatialBeanService.getStopsByLocation(...)`
-
-At this point, your eyes have probably glazed over, and I haven't even
mentioned the _implementing_ classes for all those services. Why so many
service interfaces? Why the insistence on separation into an interface and
implementing class when there is often a one-to-one mapping? I have a
number of reasons:
-
- * Allows me to easily insert caching, logging, and other aspects without
modifying the implementing class using Java interface proxies
- * Easier unit testing
- * Implementation detail hiding
-
-Unfortunately, the result is that it can be tricky to trace through the
code to figure out what exactly is going on. Using a good IDE like Eclipse
can ease some of the pain, but there it is.
-
-When everything is done executing, a `StopsWithArrivalsAndDeparturesBean`
response bean will have been properly populated and returned from the
`TransitDataService` implementation.
-
-= The View Layer: JSP =
-
-At this point, control returns to Struts, which passes control now to the
view layer. Because we are using the Struts Convention plugin, the Struts
library automatically looks for a view layer handler in a standard place.
Specifically, it looks for:
-
-{{{
-src/main/webapp/WEB-INF/content/where/standard/stop.jspx
-}}}
-
-If we examine the JSP file, you'll find the standar mix of HTML and custom
JSP tags. The tag prefixs are defined using standard XML namespace
declarations at the top of the file:
-
-{{{
-<html xmlns:jsp="http://java.sun.com/JSP/Page"
xmlns:c="http://java.sun.com/jsp/jstl/core" xmlns:s="/struts-tags">
-}}}
-
-We are using three sets of taglibs:
-
- # `<jsp:tags />` - the JSP xml-specific taglibs
- # `<c:tags />` - the JSP Standard Tag Library
- # `<s:tags />` - the Struts taglibs
-
-The Struts tags are the most complex tags but also the most frequently
used, so we will discuss them in detail.
-
-
-= Struts Taglibs and the !ValueStack =
-
-Struts internally maintains a stack of objects that are automatically
referenced by tags (called the ValueStack). When we first enter the JSP
page, that stack includes just one object: the Action bean that was just
used to handle the request. Consider the tag:
-
-{{{
-<s:set name="stop" value="result.stop" />
-}}}
-
-This tag is going to set a variable named `stop` using the value
expression above. That expression automatically get generated to a Java
call like:
-
-{{{
-STACK.getTop().getResult().getStop()
-}}}
-
-Remember that our StopByNumberAction is at the top of the stack, so
`getTop()` will return it. The `getResult()` method of StopByNumberAction
will next return a `StopWithArrivalsBean` bean, and then the call to
`getStop()` will return a `StopBean` and so on and so forth.
-
-The Java bean property syntax used above is handy, but you can also just
call straight up methods as well. The tag snippet:
-
-{{{
-<s:set name="now" value="getNow()" />
-}}}
-
-ends up as a call to `StopAction.getNow()`, for example.
-
-All those calls to `<s:set .../>` are just defining a few convenience
variables, so that information can be accessed later on. For example:
-
-{{{
-<s:property value="#stop.name" />
-}}}
-
-Note the use of the `#`. This tells the tag to look for a variable named
`stop` which we defined earlier, as opposed to looking for a `stop`
property on the StopAction.
-
-We keep mentioning the value stack, so let's mention an instance where an
object gets pushed onto the stack. Consider:
-
-{{{
-<s:iterator value="result.predictedArrivals">
- ...
-</s:iterator>
-}}}
-
-The `<s:iterator .../>` tag is a simple loop construct. Specifically, it
ends up iterating over the `List<PredictedArrivalBean>` returned by the
StopWithArrivals bean returned by the `getResult()` call to the
StopByNumberAction bean currently at the top of the stack. For each
iteration, the PredictedArrivalBean is pushed onto the top of the stack and
popped off at the end. Now when additional calls are made to
`<s:property .../>` or other tags, the PredictedArrivalBean will be
consulted first as the top of the stack.
-
-You should hopefully be able to trace through the remainder of the JSP
page at this point and have a rough grasp of how beans produced in the
Action phase of the process pipeline are accessed in the JSP view phase of
the pipeline.
-
-
-= The !SiteMesh Decorators =
-
-Once the HTML is generated, we are almost done. The generic look and feel
of the site is now applied using the [http://www.opensymphony.com/sitemesh/
SiteMesh] framework. !SiteMesh allows you to apply _decorators_ that apply
additional templating to a rendered JSP page.
-
-Our decorators are defined in:
-
-{{{
-src/main/webapp/WEB-INF/decorators.xml
-}}}
-
-The `decorators.xml` file matches various URL patterns to templates. The
relevant section for our request is:
-
-{{{
-<decorator name="main" page="main.jspx">
- <pattern>/*</pattern>
-</decorator>
-}}}
-
-which defines a mapping to the `main.jspx` template. All the templates
are in:
-
-{{{
-src/main/webapp/WEB-INF/decorators
-}}}
-
-The template is just another JSP page that renders like any other JSP,
with the addition of the `<decorator:* />` tag lib. There are really only
two tags to worry about:
-
-{{{
-<decorator:head />
-<decorator:body />
-}}}
-
-These just include the contents of the `<head />` and `<body />` tags from
previously-rendered JSP (stop.jspx in our case) and insert them into the
new JSP, effectively wrapping the original content.
-
-Now, finally, the response is ready to be sent back to the client.
+#labels Deprecated
+Moved to
https://github.com/OneBusAway/onebusaway-application-modules/wiki/An-Example-Webpage-Request

Reply all
Reply to author
Forward
0 new messages