There's nothing better than a detailed example to provide some insight into the concepts presented above. In the following example, we'll go step-by-step through a typical request sent to the SoftSlate Commerce application, touching on each of the configuration files, Java classes, and JSP templates used to process it. The example we'll use is a request from a user to add an item to the cart.
The user submits the "Add to Cart" form from a product detail page. As you can see, the form contains an input box for the quantity, as well as any number of form elements describing customer-selected "attributes" for the product (in this case, "Frame" and "Size" are the two attributes assigned to this product).
The Web Controller or Struts layer identifies the action mapping
corresponding to the URL of the request. In this case, the URL is
/CartAdd.do . The Struts
ActionServlet looks up the corresponding action mapping
and finds it in the
<action path="/CartAdd" type="com.softslate.commerce.customer.order.CartAddAction" name="cartAddForm" validate="true" scope="request" input="/Product.do"> <forward name="failure" path="/Product.do"/> <forward name="success" path="cart.full"/> </action>
The Web Controller or Struts layer identifies and invokes the Struts
action form corresponding to the request. The above action mapping
refers to the "cartAddForm" form bean, which is defined at the top of the same
<form-bean name="cartAddForm" type="com.softslate.commerce.customer.order.CartAddForm"> </form-bean>
Because the action mapping's
validate attribute is set to
true, Struts knows that the request must be validated. In Struts, this means that the
validate method of the action form
must be invoked.
validate method of
validates the request's parameters. In this case,
CartAddForm makes sure a postitive integer is present for
the quantity to be added, and that if any of the product's attributes are required,
they are present in the request.
More details about the add to cart validation is available in the
API Documentation for
If the result of the validation is one or more errors, the request gets forwarded to
the value of the action mapping's
input attribute. If there are
no errors, Struts proceeds to invoke the
of the action class
. We'll assume a successful result without errors.
execute method of
is invoked to process the request. In this case,
CartAddAction starts by creating an instance of
, invoking its
// Process the items CartProcessor cartProcessor = (CartProcessor) baseForm .getBusinessObjectFactory().createObject( "cartProcessorImplementer"); Map results = cartProcessor.processAddItems(PropertyUtils .describe(baseForm));
At this point, control of the request is passed from the Web Controller or Struts layer, to the Business layer.
Whenever an object in the Business layer is created, the
Now in the Business layer, the
processAddItems method of
is invoked. This method handles the business logic involved with the
request to add an item to the cart. Namely, it instantiates the user's cart if it
doesn't already exist. A user's cart is represented as an instance of
. It then parses the incoming parameters and creates an instance of
to represent the order item.
After performing some validations against the database, processing inventory, and processing discounts, it finally hands things off to the Data Access layer to record the results of the request in the database:
OrderGatewayDAO orderGatewayDAO = (OrderGatewayDAO) getDaoFactory() .createDAO("orderGatewayDAOImplementer"); orderGatewayDAO .processOrderItems(getUser(), newOrderItems, results);
Whenever an object in the Data Access layer is created, the
Now in the Data Access layer, the
processOrderItems method of
is invoked. This method synchronizes the state of the user's cart with
the database. Namely, it will insert or update records into the
sscOrder and related tables, storing the new order item in the
The DAO will use Hibernate mappings to synchronize the application's objects with
the database. In this case, the Hibernate mapping file
and other mappings files next to it are used to synchronize the application's objects
with the database tables.
Some DAOs will use HQL (Hibernate Query Language) mappings to communicate with the
database. In cases where data is being retrieved from the database, the DAO will
employ the HQL queries in the
queries.hbm.xml files in the
WEB-INF/classes/resources subdirectories to query the
database through Hibernate.
Assuming a successful result, control passes back to
. Assuming everything goes well, control will pass back to the Web
Controller or Struts layer. In this case,
will perform some additional processing of the request. In particular, depending on
the application's inventory settings, the results of the processing by the Business
layer might indicate that one or more messages be displayed to the user concerning
inventory levels, or that one or more "low stock emails" be sent to the store's
When it is finished processing these possibilities, the
execute method of
CartAddAction forwards the request to a Struts action
The Web Controller or Struts layer looks up the action forward returned by the action class. The Struts action forwards are defined back in the Struts action mapping for the request. In this case the following two action forwards can be returned:
<forward name="failure" path="/Product.do"/> <forward name="success" path="cart.full"/>
If it's a failure, control of the request is passed to the "/Product.do" URL. In other words, the user is sent back to the product page where any errors that occured are displayed.
If on the other hand everything went well and the processing succeeded, control is passed to "cart.full", which is not a URL but rather a Tiles definition. Forwards that use this sort of dot notation identify Tiles definitions.
It's at this point that control passes to the Presentation layer.
The Presentation layer looks up the Tiles definition corresponding to
the action forward. In this case, it finds the "cart.full" Tiles
definition in the
<definition name="cart.full" extends="core.baseLeftLayout"> <put name="pageTitleKey" value="page.cart"/> <put name="subMenu" value="product.breadcrumbs" /> <put name="body" value="cart.fullLayout" /> </definition>
Tiles definitions can both extend other definitions, and include other
definitions under them. As you can see, "cart.full" extends the
"core.baseLeftLayout" definition, which is defined in the
<definition name="core.baseLeftLayout" path="/WEB-INF/layouts/default/core/leftLayout.jsp" controllerUrl="/LayoutAction.do"> <put name="beforeHTML" value="/WEB-INF/layouts/default/core/empty.jsp" /> <put name="htmlHead" value="/WEB-INF/layouts/default/core/htmlHead.jsp" /> <put name="tracking" value="/WEB-INF/layouts/default/core/tracking.jsp" /> <put name="header" value="/WEB-INF/layouts/default/core/header.jsp" /> <put name="error" value="/WEB-INF/layouts/default/core/error.jsp" /> <put name="message" value="/WEB-INF/layouts/default/core/message.jsp" /> <put name="leftSide" value="core.leftSide" /> <put name="rightSide" value="core.rightSide" /> <put name="subMenu" value="/WEB-INF/layouts/default/core/empty.jsp" /> <put name="body" value="/WEB-INF/layouts/default/core/empty.jsp" /> <put name="footer" value="/WEB-INF/layouts/default/core/footer.jsp" /> <put name="afterHTML" value="/WEB-INF/layouts/default/core/empty.jsp" /> </definition>
Here you can start to understand how Tiles organizes the JSP templates used to
display the results of every request. The "cart.full" definition extends
"core.baseLeftLayout", which identifies many of the JSP templates used to display
the application's HTML. Note that "core.baseLeftLayout" indicates that a JSP file
empty.jsp should be use for the "body" of the page.
Fortunately, "cart.full" overrides this attribute - otherwise, only an empty space
would be displayed in the page's body.
"cart.full" identifies another Tiles definition should be used for the body of the
page: "cart.fullLayout". This definition appears just below "cart.full" in the
<definition name="cart.fullLayout" path="/WEB-INF/layouts/default/order/cart.jsp"> <put name="couponFormGuts" value="/WEB-INF/layouts/default/order/couponFormGuts.jsp" /> </definition>
With this definition we've now seen nearly all of the JSP templates used to generate
the response. In particular, we can guess that
going to provide the guts of the screen for us.
The Presentation layer forwards the request to JSP template
correponding to the
path attribute of the Tiles
definition. In this case, because "cart.full" extends
"core.baseLeftLayout", the request is forwarded to
The JSP templates are processed, including processing of the Tiles tags.
A peek at
leftLayout.jsp will give you a good idea of how the
various attributes of each Tiles definition are used. For example, this line is the
point at which the value of the "body" attribute (in our case,
cart.jsp) is included:
leftLayout.jsp is processed in this way, including
each of the JSP templates referred to by their Tiles attributes. The result is an HTML
page displaying the contents of the user's cart, including the new item that has just
been added to it.
SoftSlate Commerce extends the Tiles framework to first look inside the