Contact Us 1-800-596-4880

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:

  • On a Unix/Linux system, run the following command:

<MULE_HOME>/bin/mule start
  • On a Windows system, go to the <MULE_HOME>\bin by running the following command:

cd <MULE_HOME>\bin

Then type mule and press Enter. Running mule.bat also starts the server.

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 <MULE_HOME>/apps/mule-example-bookstore-3.3.1/mule-config.xml.

To update the timestamps, run the following command:

touch <MULE_HOME>/apps/mule-example-bookstore-3.3.1/mule-config.xml

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.

<app_root>/webapps/bookstore

Admin Web App

Allows administrative access to the book catalog and statistics

<app_root>/webapps/bookstore-admin

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:

OOO-diagram_actual

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:

OOO-diagram_realworld

The Bookstore example provides two Web apps, which will be available at the following URLs:

Details on directory structure

The files for this example are in the directory <MULE_HOME>/examples/bookstore. This directory includes the file mule-example-bookstore-3.3.1.zip, which contains all of the files necessary to run the application, including the compiled Java classes.

You deploy the app by copying the file mule-example-bookstore-3.3.1.zip to the directory <MULE_HOME>/apps. Mule automatically extracts the contents of the file to the directory <MULE_HOME>/apps/mule-example-bookstore-3.3.1. When starting and running the application, Mule reads only from this directory.

Contents of <MULE_HOME>/examples/bookstore:

  • src: Directory that contains all source code files

  • mule-example-bookstore-3.3.1.zip: Zip file with the application, including the compiled Java classes

  • pom.xml: Maven Project Object Model file (XML representation of the Maven project)

  • README.txt: Contains a basic overview of the example and instructions for installing and running

Contents of <MULE_HOME>/apps/mule-example-bookstore-3.3.1:

  • classes: Directory with configuration files and subdirectories containing compiled Java classes. This directory contains the following important files:

    • bookstore-config.xml: Main configuration file for the example, including flow definitions

    • email.properties: Configuration file for email messaging (mail server host, credentials, etc.)

    • log4j.properties: Apache log4j configuration file

  • mule-config.xml: Mule servlet configuration file for the example

  • webapps: Contains the two Web apps, provided in the example, bookstore and bookstore-admin. The name of each directory determines the URI of the Web app, within the URL defined in <MULE_HOME>/apps/mule-example-bookstore-3.3.1/mule-config.xml. Each Web app directory contains:

    • .jsp files

    • WEB-INF directory with the web.xml configuration file for the app

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

CatalogPublicInterface

Listens for catalog requests using an HTTP Inbound Endpoint, then uses the CXF Module to call the Catalog Service using the getBooks() method (defined in the CatalogServiceImpl.java class)

OrderService

Listens for order requests using an HTTP Inbound Endpoint, then uses the CXF Module to call the Order Service

DataWarehouse

Uses In Memory (VM) inbound and outbound endpoints to get book sales statistics from the Data Warehouse Service

EmailNotificationService

Emails notification of purchase to the email address supplied by the customer

CatalogAdminInterface

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

catalog.jsp

Provides the interface for searching for a book in the catalog

order.jsp

Provides the interface for ordering a book

WEB-INF

Directory containing the Web app’s configuration

WEB-INF/web.xml

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:

public.web.page

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

admin.jsp

Provides the admin interface served via HTTP

WEB-INF

Directory containing the Web app’s configuration

WEB-INF/web.xml

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>
admin.web.page

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 be CatalogService

  • 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