<MULE_HOME>/bin/mule start
Bookstore Example
This document assumes that you are familiar with Mule ESB. For an overview of basic operations, such as starting the server and locating Mule files, consult the Quick Start Guide to Mule ESB Server and the Management Console.
Set Up
The Bookstore example is configured to run in an embedded Jetty servlet container from within the Mule server.
To run the Bookstore example, copy the file <MULE_HOME>/examples/bookstore/mule-example-3.3.1.zip
to the <MULE_HOME>/apps
directory. Then start the Mule server, if it is not already running.
<MULE_HOME> is the root directory of your Mule installation, for example /opt/Mule/mule-standalone-3.3.1 .
|
How to start the Mule server
There are several ways to start/stop the Mule server:
Usually, the simplest way to start the server is by using the command line:
Then type |
How to reload the Bookstore app without restarting the Mule server (Unix)
If you modify the Bookstore application while Mule is running, you can reload the application without restarting Mule by "touching" (updating the timestamps of) the file To update the timestamps, run the following command:
Mule will automatically reload the application, activating any modifications. |
How It Works
This Bookstore example application allows customers to search for and order books through a Web interface. An administrator can use a separate Web interface to add books to the book catalog, and to check sales statistics.
The application bundles two separate Web apps, described in the table below:
Web App | Description | Directory (when deployed) |
---|---|---|
Bookstore Web App |
Allows customers to search the catalog and order books. |
|
Admin Web App |
Allows administrative access to the book catalog and statistics |
|
Each app includes the Java Server Pages (JSPs) which allow user interaction with the catalog.
The Bookstore Web App interacts with the following services:
-
Catalog Service: Defined in the
CatalogServiceImpl.java
Java class. Contains a simple hash map with book titles and authors. In a real-life scenario the catalog would be a database. -
Order Service: Defined in the
OrderServiceImpl.java
Java class. This service communicates with the following services:-
Email Notification Service*: Sends a confirmation email to the address specified by the customer when ordering a book. Defined in
OrderToEmail
, a String to Email transformer -
Data Warehouse Service*: Keeps tracks of book sales statistics. Defined in
DataWarehouse.java
-
The Admin Web App interacts with the following services:
-
Catalog Service
-
Data Warehouse Service
The following diagram illustrates the architecture of the Bookstore example application as provided in Mule:
For ease of deployment, both Web apps are bundled together in a single Mule application. In a real world scenario these Web apps would be deployed separately, using an architecture similar to the following:
The Bookstore example provides two Web apps, which will be available at the following URLs:
-
Bookstore App (search for and order books):
http://localhost:8083/bookstore
-
Bookstore Admin App (add books and get order statistics):
http://localhost:8083/bookstore-admin
Details on directory structure
The files for this example are in the directory You deploy the app by copying the file Contents of
Contents of
|
Flows
The application’s five flows are defined in the file bookstore-config.xml
. This file is at <MULE_HOME>/examples/bookstore/src/main/resources
. (Once the application is running, the actual file used by Mule is at <MULE_HOME>/apps/mule-example-bookstore-3.3.1/classes
.)
View the XML
<?xml version="1.0" encoding="UTF-8"?>
<mule xmlns="http://www.mulesoft.org/schema/mule/core" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:spring="http://www.springframework.org/schema/beans"
xmlns:http="http://www.mulesoft.org/schema/mule/http"
xmlns:vm="http://www.mulesoft.org/schema/mule/vm" xmlns:cxf="http://www.mulesoft.org/schema/mule/cxf"
xmlns:smtp="http://www.mulesoft.org/schema/mule/smtp" xmlns:smtps="http://www.mulesoft.org/schema/mule/smtps"
xmlns:email="http://www.mulesoft.org/schema/mule/email"
xmlns:servlet="http://www.mulesoft.org/schema/mule/servlet"
xmlns:doc="http://www.mulesoft.org/schema/mule/documentation"
xsi:schemaLocation="
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-current.xsd
http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
http://www.mulesoft.org/schema/mule/vm http://www.mulesoft.org/schema/mule/vm/current/mule-vm.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-current.xsd
http://www.mulesoft.org/schema/mule/cxf http://www.mulesoft.org/schema/mule/cxf/current/mule-cxf.xsd
http://www.mulesoft.org/schema/mule/smtp http://www.mulesoft.org/schema/mule/smtp/current/mule-smtp.xsd
http://www.mulesoft.org/schema/mule/smtps http://www.mulesoft.org/schema/mule/smtps/current/mule-smtps.xsd
http://www.mulesoft.org/schema/mule/email http://www.mulesoft.org/schema/mule/email/current/mule-email.xsd
http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd
http://www.mulesoft.org/schema/mule/servlet http://www.mulesoft.org/schema/mule/servlet/current/mule-servlet.xsd">
<context:property-placeholder location="email.properties" />
<!-- Configure some properties to work with GMail's SMTP -->
<smtp:gmail-connector name="emailConnector" />
<!-- Use this as a poor man's message queue, in the real world we would use JMS -->
<vm:connector name="vmQueues" />
<!-- This queue contains a feed of the latest statistics generated by
the Data Warehouse (it should really be a LIFO queue) -->
<vm:endpoint name="stats" path="statistics" exchange-pattern="one-way" />
<!-- Convert request parameters to Book object -->
<custom-transformer name="HttpRequestToBook" class="org.mule.example.bookstore.transformers.HttpRequestToBook" />
<!-- Format response to be a nice HTML page -->
<custom-transformer name="AddBookResponse" class="org.mule.example.bookstore.transformers.AddBookResponse" />
<custom-transformer name="OrderToEmail" class="org.mule.example.bookstore.transformers.OrderToEmailTransformer" />
<custom-transformer name="StringToEmail" class="org.mule.transport.email.transformers.StringToEmailMessage"/>
<spring:bean class="org.mule.example.bookstore.CatalogServiceImpl" name="CatalogService" init-method="initialise"/>
<message-properties-transformer name="setHtmlContentType" overwrite="true">
<add-message-property key="Content-Type" value="text/html" />
<!-- Tomcat lowercases headers, need to drop this old one too -->
<delete-message-property key="content-type" />
</message-properties-transformer>
<!-- Administration interface -->
<flow name="CatalogAdminInterface">
<inbound-endpoint address="servlet://catalog" exchange-pattern="request-response" transformer-refs="HttpRequestToBook"
responseTransformer-refs="AddBookResponse setHtmlContentType" doc:name="Administration interface"/>
<component doc:name="Catalog Service">
<spring-object bean="CatalogService" />
</component>
</flow>
<!-- Public interface -->
<flow name="CatalogPublicInterface">
<http:inbound-endpoint address="http://0.0.0.0:8777/services/catalog" exchange-pattern="request-response" doc:name="Public interface"/>
<cxf:jaxws-service serviceClass="org.mule.example.bookstore.CatalogService" />
<component doc:name="Catalog Service">
<spring-object bean="CatalogService"/>
</component>
</flow>
<flow name="OrderService">
<http:inbound-endpoint address="http://0.0.0.0:8777/services/order" exchange-pattern="request-response" doc:name="Public order interface"/>
<cxf:jaxws-service serviceClass="org.mule.example.bookstore.OrderService" />
<component doc:name="Order Service">
<singleton-object class="org.mule.example.bookstore.OrderServiceImpl"/>
</component>
<async>
<vm:outbound-endpoint path="emailNotification" exchange-pattern="one-way" doc:name="Email Notification"/>
<vm:outbound-endpoint path="dataWarehouse" exchange-pattern="one-way" doc:name="Data Warehouse"/>
</async>
</flow>
<flow name="EmailNotificationService">
<vm:inbound-endpoint path="emailNotification" exchange-pattern="one-way" doc:name="Email Notification"/>
<smtps:outbound-endpoint user="${user}" password="${password}" host="${host}" from="${from}" subject="Your order has been placed!"
transformer-refs="OrderToEmail StringToEmail" doc:name="Send notification email"/>
</flow>
<flow name="DataWarehouse">
<vm:inbound-endpoint path="dataWarehouse" exchange-pattern="one-way" doc:name="Data Warehouse" />
<component doc:name="Data Warehouse component">
<singleton-object class="org.mule.example.bookstore.DataWarehouse" />
</component>
<vm:outbound-endpoint ref="stats" transformer-refs="setHtmlContentType" doc:name="Statistics queue"/>
</flow>
</mule>
The following table details the flows defined for the application.
Flow | Description |
---|---|
|
Listens for catalog requests using an HTTP Inbound Endpoint, then uses the CXF Module to call the Catalog Service using the |
|
Listens for order requests using an HTTP Inbound Endpoint, then uses the CXF Module to call the Order Service |
|
Uses In Memory (VM) inbound and outbound endpoints to get book sales statistics from the Data Warehouse Service |
|
Emails notification of purchase to the email address supplied by the customer |
|
Invoked by the Admin Web app, uses a Servlet Endpoint to convert HTML into a book object for the Catalog Service |
Bookstore Webapp
Directory: <MULE_HOME>/mule-example-bookstore-3.3.1/webapps/bookstore
File |
Description |
|
Provides the interface for searching for a book in the catalog |
|
Provides the interface for ordering a book |
|
Directory containing the Web app’s configuration |
|
Configuration file for the Web app |
When a customer opens the public Web page, the Bookstore Web app file web.xml
loads the file catalog.jsp
, which contains the interface that allows customers to search through the catalog. The Web app displays the interface in the HTML page for customers.
View the file web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<display-name>On-line Bookstore</display-name>
<description>Mule-powered On-line Bookstore</description>
<welcome-file-list>
<welcome-file>catalog.jsp</welcome-file>
</welcome-file-list>
</web-app>
The image below shows the Web page displayed by the application:
When a customer searches the catalog, the Web application calls the Catalog
service using the getBooks()
method. To do so, the application sends the request over the CXF transport cxf:http://localhost:8777/services/catalog
. CXF marshals the request between Java and WSDL/XML. The Catalog service replies by sending the Book
object as an XML response marshaled by CXF, which the service displays on the Web page.
Admin Webapp
Directory: <MULE_HOME>/mule-example-bookstore-3.3.1/webapps/bookstore-admin
File |
Description |
|
Provides the admin interface served via HTTP |
|
Directory containing the Web app’s configuration |
|
Configuration file for the Web app |
When an administrator opens the admin Web page, the Bookstore Admin Web App file web.xml
loads the file admin.jsp
, which contains the interface that allows the user to add books to the catalog.
View the file web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<display-name>Bookstore Administration</display-name>
<description>Administration console for the Mule-powered On-line Bookstore</description>
<!-- The Mule configuration is provided as a context parameter -->
<context-param>
<param-name>org.mule.config</param-name>
<param-value>bookstore-config.xml</param-value>
</context-param>
<!-- This listener will start up Mule inside the webapp -->
<listener>
<listener-class>org.mule.config.builders.MuleXmlBuilderContextListener</listener-class>
</listener>
<!-- This servlet will route a URL of "/bookstore-admin/services/foo"
to the inbound endpoint "servlet://foo" in Mule -->
<servlet>
<servlet-name>muleServlet</servlet-name>
<servlet-class>org.mule.transport.servlet.MuleRESTReceiverServlet</servlet-class>
<!-- Responses from the servlet are of type HTML by default -->
<init-param>
<param-name>org.mule.servlet.default.content.type</param-name>
<param-value>text/html</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>muleServlet</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>admin.jsp</welcome-file>
</welcome-file-list>
</web-app>
When an administrator adds a book using the Admin Web App, the app sends the information as an HTTP request (using the POST method <form method="POST" action="../catalog">
) over the Servlet transport to servlet://catalog
. The CatalogAdminInterface
flow transforms the HTTP request to a Book
object, and passes it via the addBook
method to the Catalog Service.
Java Classes
The Java class files for the Bookstore Admin Web app are located in <MULE_HOME>/examples/bookstore/src/main/java/org/mule/example/bookstore
. The CatalogServiceImpl.java
class defines the methods addBook()
and getBooks()
, for adding and getting books. The OrderServiceImpl.java
class defines the orderBook()
method.
The DataWarehouse.java
class defines methods for updating statistics on the page, retrieving the best seller, and printing the statistics on the page.
The DataWarehouse.java
class defines the updateStats
method for updating statistics on the page, the getBestSeller
for getting the title of the best-selling book, and the printHtmlStats()
method for printing the statistics on the page.
The domain objects such as Book
and Order
are also defined in Java classes in the same directory.
In addition to defining the various methods, the Java files also contain annotations. For example, CatalogServiceImpl.java
contains the following annotation:
@WebService(serviceName="CatalogService", endpointInterface="org.mule.example.bookstore.CatalogService")
-
@WebService
: lets CXF know that this is a JAX-WS service -
serviceName
: Specifies that the service name in the WSDL will beCatalogService
-
endpointInterface
: Controls what interface CXF uses to build your WSDL. If not specified, CXF will use your Web service implementation class to generate the WSDL (and will therefore expect any@WebParam
and@WebResult
annotations to be located there)
Java does not store parameter names in class files, so parameters for WSDL must be supplied with annotations. In the extract below, the @WebResult
and @WebParam
annotations define the parameter names for WSDL:
@WebResult(name="order")
Order orderBook(@WebParam(name="book") Book book,
@WebParam(name="quantity") int quantity,
@WebParam(name="address") String address,
@WebParam(name="email") String email);
Transformers
The <MULE_HOME>/examples/bookstore/src/main/java/org/mule/example/bookstore/transformers
directory contains the transformers for the Bookstore application.
-
AddBookResponse.java: Adds a book to the response message and wraps it in an HTML body, using the HTML template in
examples/bookstore/src/main/java/org/mule/example/bookstore/web
-
OrderToEmailTransformer.java: Composes an e-mail notification message for the customer, based on the Book Order. The
<string-to-email-transformer>
from the Email transport converts this text to an email message -
HttpRequestToBook: Transforms a Map of HttpRequest parameters into a Book object