APEssentials3.7 Student Manual

User Manual: Pdf

Open the PDF directly: View PDF PDF.
Page Count: 267

DownloadAPEssentials3.7 - Student Manual
Open PDF In BrowserView PDF
Anypoint Platform
Essentials
Student Manual
Mule Runtime 3.7.1
Anypoint Studio 5.2.1
August 7, 2015

1

Table of Contents
SETUP INSTRUCTIONS ...............................................................................................................4	
  
MODULE 2: BUILDING INTEGRATION APPLICATIONS WITH ANYPOINT STUDIO ...7	
  
Walkthrough 2-1: Create your first Mule application ............................................................................. 8	
  
Walkthrough 2-2: Run, test, and debug an application ....................................................................... 12	
  
Walkthrough 2-3: Read and write message properties ....................................................................... 17	
  
Walkthrough 2-4: Read and write variables ........................................................................................ 20	
  

MODULE 3: CONSUMING WEB SERVICES .......................................................................... 23	
  
Walkthrough 3-1: Consume a RESTful web service ........................................................................... 24	
  
Walkthrough 3-2: Pass arguments to a RESTful web service ............................................................ 29	
  
Walkthrough 3-3: Consume a RESTful web service that has a RAML definition ................................ 33	
  
Walkthrough 3-4: Consume a SOAP web service .............................................................................. 40	
  

MODULE 4: CONNECTING TO ADDITIONAL RESOURCES ............................................ 45	
  
Walkthrough 4-1: Connect to a database (MySQL) ............................................................................ 46	
  
Walkthrough 4-2: Connect to a file (CSV) ........................................................................................... 52	
  
Walkthrough 4-3: Connect to a JMS queue (ActiveMQ) ..................................................................... 57	
  
Walkthrough 4-4: Connect to a SaaS application (Salesforce) ........................................................... 64	
  
Walkthrough 4-5: Find and install not-in-the-box connectors .............................................................. 73	
  

MODULE 5: TRANSFORMING DATA .................................................................................... 76	
  
Walkthrough 5-1: Load external content into a message .................................................................... 77	
  
Walkthrough 5-2: Write your first DataWeave transformation ............................................................. 80	
  
Walkthrough 5-3: Transform basic Java, JSON, and XML data structures ......................................... 85	
  
Walkthrough 5-4: Transform complex data structures ........................................................................ 91	
  
Walkthrough 5-5: Use DataWeave operators ................................................................................... 104	
  
Walkthrough 5-6: Transform data sources that have associated metadata ...................................... 115	
  
Walkthrough 5-7: Pass arguments to a SOAP web service .............................................................. 125	
  
Walkthrough 5-8: Transform a data source to which you add custom metadata .............................. 129	
  

MODULE 6: REFACTORING MULE APPLICATIONS ....................................................... 135	
  
Walkthrough 6-1: Separate applications into multiple configuration files .......................................... 136	
  
Walkthrough 6-2: Encapsulate global elements in a separate configuration file ............................... 141	
  
Walkthrough 6-3: Create and run multiple applications .................................................................... 143	
  
Walkthrough 6-4: Create and reference flows and subflows ............................................................. 150	
  

2

MODULE 7: HANDLING ERRORS ........................................................................................ 156	
  
Walkthrough 7-1: Handle a messaging exception ............................................................................. 157	
  
Walkthrough 7-2: Handle multiple messaging exceptions ................................................................ 160	
  
Walkthrough 7-3: Create and use global exception handlers ........................................................... 168	
  
Walkthrough 7-4: Specify a global default exception strategy .......................................................... 172	
  

MODULE 8: CONTROLLING MESSAGE FLOW ................................................................. 175	
  
Walkthrough 8-1: Multicast a message ............................................................................................. 176	
  
Walkthrough 8-2: Route messages based on conditions .................................................................. 182	
  
Walkthrough 8-3: Filter messages .................................................................................................... 188	
  
Walkthrough 8-4: Pass messages to an asynchronous flow ............................................................. 194	
  

MODULE 9: PROCESSING RECORDS ................................................................................. 196	
  
Walkthrough 9-1: Process items in a collection individually .............................................................. 197	
  
Walkthrough 9-2: Create a batch job for records in a file .................................................................. 202	
  
Walkthrough 9-3: Create a batch job for records in a database ........................................................ 207	
  
Walkthrough 9-4: Restrict processing using a poll watermark .......................................................... 210	
  
Walkthrough 9-5: Restrict processing using a message enricher and a batch step filter .................. 214	
  

MODULE 10: BUILDING RESTFUL INTERFACES WITH RAML AND APIKIT ............ 222	
  
Walkthrough 10-1: Use API Designer to define an API with RAML .................................................. 223	
  
Walkthrough 10-2: Use API Designer to simulate an API ................................................................. 228	
  
Walkthrough 10-3: Use Anypoint Studio to create a RESTful API interface from a RAML file ......... 234	
  
Walkthrough 10-4: Use Anypoint Studio to implement a RESTful web service ................................ 239	
  

MODULE 11: DEPLOYING APPLICATIONS ...................................................................... 244	
  
Walkthrough 11-1: Use application properties .................................................................................. 245	
  
Walkthrough 11-2: Dynamically specify property files ....................................................................... 250	
  
Walkthrough 11-3: (Optional) Deploy an application to the cloud ..................................................... 252	
  
Walkthrough 11-4: (Optional) Deploy an application on-prem .......................................................... 259	
  

3

Setup instructions
To complete the exercises in this class, you need:
1. A computer with at least 3GB RAM, 2GHz CPU, and 4GB storage
https://developer.mulesoft.com/docs/display/current/Hardware+and+Software+Requirements
These are the requirements to run Anypoint Studio.
2. Internet access with access to the following ports and hosts:
Port

Host

80

mulesoft.com (and subdomains)

80

mulesoft-training.com (and subdomains)

80

cloudhub.io (and subdomains)

80

salesforce.com (and subdomains)

3306

iltdb.mulesoft-training.com

61616

54.69.115.37

Note: You can use telnet to test the availability of these ports. For example, in a
Terminal/Command window, enter the following command and see if it connects:
telnet iltdb.mulesoft-training.com 3306
If you are using Windows and need to install a Telnet Client, see
https://technet.microsoft.com/en-us/library/Cc771275(v=WS.10).aspx.
If you have restricted internet access and cannot access some of these ports and hosts, you
can instead use VirtualBox and a MuleSoft Training server image. Instructions for installing and
setting up the server are included below.
You also need to install and/or set up BEFORE class:
1. Java SE Development Kit 8 (JDK 8 NOT JDK 6 or JDK 7)
http://www.oracle.com/technetwork/java/javase/downloads/index.html
This is required for Anypoint Studio.
Note: Instructions for checking what version of Java you have can be found here:
https://www.java.com/en/download/help/version_manual.xml.
2. Anypoint Studio with embedded Mule 3.7 runtime
https://www.mulesoft.com/lp/dl/studio
Download, install, and start it to make sure it runs BEFORE class.
Note: If you have any issues, make sure the JDK and Anypoint Studio are BOTH 64-bit or
BOTH 32-bit and that you have enough memory (at least 3 GB) to run Anypoint Studio.
4

3. An Anypoint Platform account
http://anypoint.mulesoft.com
Note: You can sign up for a free, 30-day trial account or you can use your company account (if
you already have one).
4. A Salesforce Developer account (NOT a standard account)
https://developer.salesforce.com/en/signup
You CANNOT use a standard account, which will not give you API access.
You should receive an activation email within 5-10 minutes of creating the account. Click the link
it contains to activate your email and set a password and password question. You will then be
logged in to Salesforce. You can also log in at http://salesforce.com using your developer
credentials.
5. A Salesforce API Access token
http://salesforce.com
In Salesforce, click your name at the top of the screen and select My Settings. On the left side
of the page, select Personal > Reset My Security Token and click the Reset Security Token
button. A security token will be sent to your email in a few minutes. You will need this token to
make API calls to Salesforce from your Mule applications.
6. Course materials
http://training.mulesoft.com/login.html
The MuleSoft Learning Management System (LMS) hosts all of the resources, links, and files for
the class. Browse to http://training.mulesoft.com/login.html and then enter your email and
password (the password used when registering for the course). If you did not set a password or
forgot it, go to http://training.mulesoft.com/reset_password.html.
Once you are logged in, click the Anypoint Platform Essentials 3.7 Course link under My
Learning Plan. Near the bottom of the page, you will see the course resources. Click the links to
download the student manual (PDF), the student files (ZIP), and the course slides (ZIP). If you
have restricted internet access and plan to use VirtualBox and the training server image, also
download the MuleSoft Training 3.6 Open Virtualization Archive (OVA).
Note: Some students find it useful to put the student manual on a tablet and reference that
during class.
7. VirtualBox (only if you have restricted internet access)
https://www.virtualbox.org/wiki/Downloads
Download, install, and set it up to run the MuleSoft Training server image BEFORE class.
Follow the setup instructions below and/or watch the setup video: https://vimeo.com/123113815.
After installing VirtualBox, open it and select File > Import Appliance. Browse to the mulesofttraining3.6.ova file you downloaded in the previous step. After the image is imported, you should
see a mulesoft-training3.6 virtual machine listed in the VirtualBox Manager.
Double-click the mulesoft-training3.6 virtual machine to start it. The server needs to be running
to complete the course exercises. Verify the server starts. You do not need to log in, but if you

5

use SSH the username and password are vagrant. To stop the virtual machine, right-click it in
the VirtualBox Manager and select Close > Power Off.
The virtual machine uses ports 61111, 8112, 4406, 8111, and 2222. If you have any port
conflicts, you will need to change these values. First, power off the virtual machine and then
click the Settings button. Click the Network button and expand the Advanced section. Click the
Port Forwarding button and change any of the host port values as necessary.
8. Mule 3.7 runtime with Mule Management Console (optional)
http://mulesoft-training.com/mule-runtime-bundle-3.7
In public classes, you will deploy to the cloud. In private classes, you will deploy to the cloud or
an on-prem, standalone Mule runtime. Step-by-step instructions for both are included in the
student manual.
If you want to follow the instructions to deploy to an on-prem Mule runtime, download the bundle
from the above link before class. You will start the server during class.

6

Module 2: Building Integration
Applications with Anypoint Studio

In this module, you will learn:
•

About Mule applications, flows, messages, and message processors.

•

To use Anypoint Studio to create flows graphically using connectors, transformers, components,
scopes, and flow control elements.

•

To build, run, test, and debug Mule applications.

•

To read and write message properties.

•

To write expressions with Mule Expression Language (MEL).

•

To create variables.

7

Walkthrough 2-1: Create your first Mule application
In this walkthrough, you will build your first Mule application. You will:
•

Create a new Mule project with Anypoint Studio.

•

Add a connector to receive requests at an endpoint.

•

Display a message in the Anypoint Studio console.

•

Set the message payload.

Launch Anypoint Studio
1. Open Anypoint Studio.
2. In the Workspace Launcher dialog box, look at the location of the default workspace; change
the workspace location if you want.

3. Click OK to select the workspace; Anypoint Studio should open.
4. If you get a Welcome Page, click the X on the tab to close it.
5. If you get an Updates Available pop-up in the lower-right corner of the application, click it and
install the available updates.

8

Create a project
6. Select File > New > Mule Project.
7. Set the Project Name to apessentials.
8. Ensure the Runtime is set to the latest version of the Mule Server.
9. Click Finish.

Create an HTTP connector endpoint to receive requests
10. Drag an HTTP connector from the palette to the canvas.

9

11. Double-click the HTTP connector endpoint.
12. In the Mule Properties view, click the Add button next to connector configuration.

13. In the Global Element Properties dialog box, look at the default values and click OK.

14. Click the Apply Changes button; the errors in the Problems view should disappear.

10

Display data
15. Drag a Set Payload transformer from the palette into the process section of the flow.
16. Drag in a Logger component and drop it after the Set Payload transformer.

Configure the Set Payload transformer
17. Double-click the Set Payload transformer.
18. In the Properties view, set the value field to Hello World.

19. Click the Configuration XML tab at the bottom of the canvas and examine the corresponding
XML.

20. Click the Message Flow tab to return to the canvas.
21. Click the Save button or press Ctrl+S to save the file.

11

Walkthrough 2-2: Run, test, and debug an application
In this walkthrough, you will run, test, and debug your first Mule application. You will:
•

Run a Mule application using the embedded Mule ESB runtime.

•

Make an HTTP request to the endpoint via a web browser or a tool like cURL or Postman.

•

Receive a response with the text Hello World.

•

Redeploy an application.

•

Use the Mule Debugger to debug an application.

Run the application
1. From the main menu bar, select Run > Run As > Mule Application.
2. Watch the Console view; it should display information letting you know that both the Mule
runtime and the apessentials application started.

12

Test the application
3. Send an HTTP request to http://localhost:8081 through a browser or tool like cURL or Postman;
you should see Hello World displayed.

4. Return to the console in Anypoint Studio.
5. Examine the last entry.

6. Click the red Terminate button to stop the application and the Mule runtime.
7. Answer the following questions.
•

What triggered all the output you saw in the console?

•

What is the last thing displayed?

•

What Java class represents the payload?

•

What are the inbound and outbound properties on the message?

Rerun the application
8. Change the value of the Set Payload transformer to a different value.
9. Click in the canvas and then save the file.

13

10. Click the Run button and watch the console; you should the application is redeployed but the
Mule runtime is also restarted.

Note: You may want to modify your perspective so you always see the console. In Eclipse, a
perspective is a specific arrangement of views in specific locations. You can rearrange the
perspective by dragging and dropping tabs and views to different locations. Use the Window
menu in the main menu bar to save and reset perspectives.

Redeploy the application
11. Change the value of the Set Payload transformer again to a different value.
12. Click the Apply Changes button in the upper-right corner of the Properties view and watch the
console; you should see the application is redeployed but the Mule runtime is not restarted.

Debug the application
13. Right-click the Set Payload component and select Toggle breakpoint.
14. Select Run > Debug or click the Debug button in the main menu bar.

14

15. In the Mule ESB Runtime window, click Yes to stop the Mule runtime and restart it connected to
the Mule Debugger.

16. In you get a Confirm Perspective Switch dialog box, click Yes.
Note: If you do not want to get this dialog box again, check Remember my decision.
17. Make another request to http://localhost:8081 with a browser or other tool like cURL or
Postman.
18. Return to Anypoint Studio and look at the Mule Debugger view.
19. Drill-down and explore the properties and variables.

20. Click the Next processor button.

15

21. Look at the new value of the payload.
22. Step through the rest of the application.
23. Stop the application and the Mule runtime.
24. Click the Mule Design tab in the upper-right corner of the application to switch perspectives.

16

Walkthrough 2-3: Read and write message properties
In this walkthrough, you will manipulate message properties. You will:
•

Write MEL expressions.

•

Use the Debugger to read inbound and outbound message properties.

•

Use the Property transformer to set outbound message properties.

Use an expression to set the payload
1. Navigate to the Properties view for the Set Payload transformer.
2. Change the value to an expression.

#['Hello	
  World']	
  
3. Click the Apply Changes button and run the application; you have to run it instead of
redeploying it because you stopped the Mule runtime when you stopped the Debugger.
4. Make a request to http://localhost:8081; the application should work as before.
5. Return to the Set Payload expression and use autocomplete to use the toUpperCase() method
to return the value in upper case.

#['Hello	
  World'.toUpperCase()]	
  
Note: Press Ctrl+Space to trigger autocomplete if it does not appear.
6. Click the Apply Changes button to redeploy the application.
7. Make a request to the endpoint; the return string should now be in upper case.

17

Use an expression to display info to the console
8. Navigate to the Properties view for the Logger component.
9. Set the message to display the http.query.params property of the message inbound properties.

10. Apply the changes and debug the application.
11. Make a request to the endpoint with a couple of query parameters; for example,
http://localhost:8081?name=pliny&type=cat.
12. Return to the Mule Debugger view and locate your query parameters.

13. Step through the application and watch the property values.
14. Navigate to the console; you should see a ParameterMap object listed.

15. Modify the Logger to display one of your query parameters.

#[message.inboundProperties.'http.query.params'.name]	
  
16. Click Apply Changes to redeploy the application and make a request to the endpoint with query
parameters again.
17. Click the Resume button in the Mule Debugger view.
18. Return to the console; you should now see the value of the parameter displayed.

18

Set an outbound property
19. Add a Property transformer between the Set Payload and Logger processors.

Note: The Message Properties transformer has been deprecated; it has been replaced by the
collection of Property, Variable, Session Variable, and Attachment transformers.
20. In the Properties view for the Property transformer, select Set Property.
21. Set the name to qpname (or some other value) and the value to an expression that evaluates
one of your query parameters.

22. Modify the Logger to display the value of this new outbound property.

#[message.outboundProperties.qpname]	
  
23. Click the Apply Changes button to redeploy the application with a connection to the Mule
Debugger.
24. Make another request to the endpoint with query parameters.
25. Click the Outbound tab in the Mule Debugger view.
26. Step to the Logger; you should see your new outbound property.

27. Click the Resume button.
28. Look at the console; you should see the value of your variable displayed.
19

Walkthrough 2-4: Read and write variables
In this walkthrough, you will create flow and session variables. You will:
•

Use the Variable transformer to create flow variables.

•

Use the Session transformer to create session variables.

Create a flow variable
1. Add a Variable transformer between the Property and Logger processors.

2. In the Variable Properties view, select Set Variable.
3. Set the name to qptype (or some other value) and the value to your second query parameter.

4. Modify the Logger to also display the value of this new variable.

#['Name:	
  '	
  +	
  message.outboundProperties.qpname	
  +	
  '	
  Type:	
  '	
  +	
  
flowVars.qptype]	
  	
  
Note: The flowVars is optional.

20

5. Save the file (or click Apply Changes) to redeploy the application in debug mode.
6. Make a request to the endpoint with query parameters again.
7. Click the Variables tab in the Mule Debugger view.
8. Step to the Logger; you should see your new flow variable.

9. Click the Resume button.
10. Look at the console; you should see the value of your outbound property and the value of your
new flow variable displayed.

Create a session variable
11. Add a Session Variable transformer between the Variable and Logger processors.

12. In the Session Variable Properties view, select Set Session Variable.
13. Set the name to color (or some other value) and give it any value, static or dynamic.

21

14. Modify the Logger to also display the session variable.

#['Name:	
  '	
  +	
  message.outboundProperties.qpname	
  +	
  '	
  Type:	
  '	
  +	
  
flowVars.qptype	
  +	
  '	
  Color:	
  '	
  +	
  sessionVars.color]	
  	
  
15. Save and redeploy the application and make a request to the endpoint with query parameters
again.
16. Click the Session tab in the Mule Debugger view.
17. Step to the Logger; you should see your new session variable.

18. Click the Resume button.
19. Look at the console; you should see the value of your session variable displayed.
20. Stop the Mule runtime.
Note: You will explore the persistence of these variables in a later module, Refactoring Mule
Applications.

22

Module 3: Consuming Web
Services

In this module, you will learn:
•

About RESTful and SOAP based web services.

•

What RAML is and how it can be used.

•

To consume RESTful web services with and without RAML definitions.

•

To consume SOAP web services.

23

Walkthrough 3-1: Consume a RESTful web service
In this walkthrough and many others, you will work on building a Mule United Airline (MUA) application
that returns flights for Delta, United, and American airlines. In this walkthrough, you will consume a
RESTful web service that returns a list of all United flights as JSON. You will:
•

Create a second flow and rename flows.

•

Add an HTTP Listener connector endpoint to receive requests at http://localhost:8081/united.

•

Add an HTTP Request connector endpoint to consume a RESTful web service for United flight
data.

Make a request to the web service
1. Make a request to the United RESTful web service URL listed in the course snippets.txt file; you
should see JSON data for the United flights returned.
2. Look at the destination values; you should see SFO, LAX, CLE, PDX, and PDF.

24

Add a new flow with an HTTP Listener connector endpoint
3. Return to apessentials.xml.
4. Drag out another HTTP connector and drop it in the canvas above the existing
apessentialsFlow.
5. Double-click the name of the flow in the canvas and give it a new name of getUnitedFlightsFlow.
Note: You can set the name in the Properties view or directly in the blue banner.

Look at the global elements
6. Click the Global Element tabs at the bottom of the canvas.
7. Select the HTTP Listener Configuration and click Edit (or double-click it).
8. In the Global Element Properties dialog box, review the HTTP_Listener_Configuration and click
OK.

25

Configure the HTTP Listener connector endpoint
9. Click the Message Flow tab.
10. Double-click the new HTTP Listener connector endpoint.
11. Set the connector configuration to the existing HTTP_Listener_Configuration.
12. Set the path to /united.

Add an HTTP Request connector endpoint
13. Drag out another HTTP connector and drop it in process section of the flow.

14. In the Properties view, change the display name to United REST Request.
15. Click the Add button next to connector configuration.

26

16. In the Global Element Properties dialog box, set the following values and click OK.
•

Name: United_REST_Request_Configuration

•

Host: Use the value for the United web service host listed in the course snippets.txt file.

•

Port: Use the value for the United web service port listed in the course snippets.txt file.

•

Base Path: /essentials/united/flights

17. In the Properties view, set the path to / and the method to GET.

27

18. Click the Global Elements tab at the bottom of the canvas and see the new global configuration
element.
19. Return to the Message Flow view.

Test the application
20. Run the application.
21. Make a request to http://localhost:8081/united; you should see JSON flight data returned.

28

Walkthrough 3-2: Pass arguments to a RESTful web service
In this walkthrough, you will retrieve United flights for a specific destination by setting the destination as
a URI parameter. You will:
•

Modify the HTTP Request connector endpoint to use a URI parameter for the destination.

•

Set the destination to a static value.

•

Set the destination to a dynamic query parameter value.

•

Create a variable to set the destination.
Note: In a later module, you will add an HTML form to the application for destination selection.

Make a request to the web service in a browser or another tool
1. Make a request to the United RESTful web service URL for a destination listed in the course
snippets.txt file; you should see JSON data for only the flights to SFO.

2. Make additional requests for destinations of LAX, CLE, PDX, or PDF.

Add a URI parameter with a static value
3. Return to apessentials.xml.
4. Double-click the United REST Request endpoint.
5. In the Properties view, click the Add Parameter button.
29

6. Set the following parameter values.
•

Parameter type: uri-param

•

Name: destination

•

Value: SFO

7. Change the United REST Request endpoint path to /{destination}.

Test the application
8. Save the application to redeploy the application and make a request to
http://localhost:8081/united/; you should only get the SFO flights.

9. Modify the United REST Request endpoint and set the URI parameter value to LAX.

30

10. Save and redeploy the application and make another request to http://localhost:8081/united/;
you should now only get the LAX flights.

Add a URI parameter with a dynamic value
11. Return to the Properties view for the United REST Request endpoint.
12. Change the value of the uri-param from LAX to an expression for the value of a query
parameter called code.

#[message.inboundProperties.'http.query.params'.code]	
  

Test the application
13. Save and redeploy the application and make a request to
http://localhost:8081/united/?code=CLE; you should only get the CLE flights.

Create a variable to set the destination
14. Add a Variable transformer before the United REST Request endpoint.

31

15. In the Variable Properties view, change the display name to Set Destination.
16. Set the operation to Set Variable and the name to destination.
17. Use a ternary expression to set the value to 'SFO' or the value of a query parameter called
code.

#[(message.inboundProperties.'http.query.params'.code	
  ==	
  empty)	
  ?	
  
'SFO'	
  :	
  message.inboundProperties.'http.query.params'.code]	
  

18. Navigate to the Properties view for the United REST connector endpoint.
19. Modify the URI parameter to use the new destination variable.

20. Save and redeploy the application and make a request to http://localhost:8081/united; you
should see only flights to SFO again.
21. Make another request to http://localhost:8081/united?code=PDX; you should now see flights to
PDX.

32

Walkthrough 3-3: Consume a RESTful web service that has a
RAML definition
In this walkthrough, you will consume a RESTful web service containing some simple bank account
data that has a RAML definition file. You will:
•

Add a third flow to the application.

•

Add an HTTP Listener connector endpoint to receive requests at http://localhost:8081/bank.

•

Add an HTTP Request connector endpoint to consume a RESTful web service defined with a
RAML file.

Add a new flow with an HTTP Listener connector endpoint
1. Return to apessentials.xml.
2. Drag out another HTTP connector and drop it in the canvas between the two existing flows.
3. Rename the flow to getBankAccountsFlow.

4. In the Properties view for the endpoint, set the connector configuration to the existing
HTTP_Listener_Configuration.
33

5. Set the path to /bank.
6. Set the allowed methods to GET.

Add an HTTP Request connector with a RAML location
7. Drag out another HTTP connector and drop it in the process section of the new flow.
8. In the Properties view, change the name to Bank REST Request.
9. Click the Add button next to connector configuration.
10. In the Global Element Properties dialog box, change the name to
Bank_REST_Request_Configuration.
11. Set the RAML location to the Banking RAML file URL listed in the course snippets file.
12. Wait for the RAML to be parsed and the host, port, and base path fields to be populated and
then click OK.
Note: If the fields did not populate, click the Reload RAML button next to the RAML location.

13. Click the Global Elements tab at the bottom of the canvas and see the new global configuration
element.

34

14. Return to the Message Flow view.

15. In the Bank REST Request Properties view, click the drop-down button for the path; you should
see the available resources (paths) for the RESTful web service defined by the RAML file.

16. Select the /customers path.
17. Set the method to GET.

35

Test the application
18. Save to redeploy the application and make a request to http://localhost:8081/bank; you should
see the customers returned as JSON.

Modify the request to use a path requiring a URI parameter
19. Return to the Properties view for the Bank REST Request endpoint.
20. Change the path to /customers/{customer_id}/accounts and the method to GET; a URI
parameter with the name customer_id should have been created automatically.
21. Set the customer_id parameter to a value of 2.

36

Test the application
22. Save to redeploy the application make a request to http://localhost:8081/bank; you should see
the account info for the customer with an ID of 2 returned as JSON.

23. Make a request and try to pass the customer ID as a URI parameter:
http://localhost:8081/bank/2; you should get a Resource not found response.

Get the value of an HTTP Listener endpoint URI parameter
24. Return to the Properties view for the HTTP Listener endpoint.
25. Change the path to use a wildcard to specify any path starting with /bank/.

37

26. Add a breakpoint to the Bank REST Request endpoint.
27. Save the file and debug the application.
28. Make a request to http://localhost:8081/bank/3.
29. In the Mule Debugger view, locate the http.request.uri and http.uri.params inbound properties.

30. Step through the rest of the application; you should still get the account info for the customer
with an ID of 2.
31. Return to the Properties view for the HTTP Listener endpoint.
32. Change the path to specify a URI parameter called ID: /bank/{ID}.

33. Save the file to redeploy the application in debug mode.
34. Make a request to http://localhost:8081/bank/4.

38

35. In the Mule Debugger view, locate the http.request.uri and http.uri.params inbound properties.

36. Step through the rest of the application; you should still get the account info for the customer
with an ID of 2

Set the HTTP Request endpoint URI parameter to a dynamic value
37. Return to the Properties view for the Bank REST Request endpoint.
38. Change the value of the customer_id uri-param from 2 to an expression for the value of an
HTTP Listener endpoint URI parameter called ID.

	
  #[message.inboundProperties.'http.uri.params'.ID]	
  

Test the application
39. Save the file and run the application.
40. Make another request to http://localhost:8081/bank/4; you should now see the account info for
the customer with an ID of 4.

39

Walkthrough 3-4: Consume a SOAP web service
In this walkthrough, you will consume a SOAP web service that returns a list of flights for Delta airlines.
You will:
•

Create a fourth flow with an endpoint to receive requests at http://localhost:8081/delta.

•

Add a Web Service Consumer connector to consume a SOAP web service for Delta flight data.

•

Use the DOM to XML transformer to display the SOAP response.

Browse the WSDL
1. Make a request to the Delta SOAP web service WSDL listed in the course snippets.txt file; you
should see the web service WSDL returned.
2. Browse the WSDL; you should find references to operations listAllFlights and findFlight.

40

Create a new flow with an HTTP Listener connector endpoint
3. Return to apessentials.xml.
4. Drag out another HTTP connector and drop it in the canvas above the existing flows.
5. Give the flow a new name of getDeltaFlightsFlow.
6. In the Properties view for the endpoint, set the connector configuration to the existing
HTTP_Listener_Configuration.
7. Set the path to /delta.
8. Set the allowed methods to GET.

Add a Web Service Consumer connector endpoint
9. Drag out a Web Service Consumer connector and drop it in the process section of the flow.

10. In the Properties view, set the display name to Delta SOAP Request.
11. Click the Add button next to connector configuration.
12. In the Global Element Properties dialog box, change the name to
Delta_Web_Service_Consumer.
13. Set the WSDL Location to the Delta SOAP web service WSDL listed in the course snippets.txt
file.

41

14. Wait for the WSDL to be parsed and the service, port, and address fields to be automatically
populated.

15. Click OK.
16. Switch to the Global Elements view and see the new global configuration element.
17. Return to the Message Flow view.
18. In the Delta SOAP Request Properties view, click the operation drop-down button; you should
see all of the web service operations listed.

19. Select the listAllFlights operation.

42

Debug the application
20. Add a Logger component after the Delta SOAP Request endpoint.
21. In the Logger Properties view, set the message to #[payload].
22. Add a breakpoint to the Logger.

23. Save the file and debug the application.
24. Make a request to http://localhost:8081/delta.
25. In the Mule Debugger view, drill-down into the payload variable.

Note: If you step to the end of the application, you will get an error.
26. Stop the Mule runtime.

Display the payload as a String
27. Add a DOM to XML transformer before the Logger.

43

Test the application
28. Save the file and run the application.
29. Make another request to http://localhost:8081/delta; you should now see the flight data returned
as a SOAP response.

30. Look at the console; you should also see the XML SOAP response displayed there.

44

Module 4: Connecting to
Additional Resources

In this module, you will learn:
•

To connect to databases.

•

To connect to files.

•

To connect to JMS queues.

•

To connect to SaaS applications.

•

To discover and install connectors not bundled with Anypoint Studio.

•

About developing your own custom connectors with Anypoint Connector DevKit.

45

Walkthrough 4-1: Connect to a database (MySQL)
In this walkthrough, you will connect to a MySQL database that contains information about American
flights. You will:
•

Create a new flow to receive requests at http://localhost:8081/american.

•

Add a Database connector endpoint that connects to a MySQL database.

•

Write a query to return all flights from the database for the static destination SFO.

•

Modify the query to use a dynamic destination from a query parameter.

•

Use the Object to String transformer to return the results as a string.
Note: You will get a destination dynamically from a form in a later module.

Create a new flow with an HTTP Listener connector endpoint
1. Return to apessentials.xml.
2. Create a new flow above the Delta flow and name it getAmericanFlightsFlow.
3. In the HTTP Properties view, set the connector configuration to the existing
HTTP_Listener_Configuration.
4. Set the path to /american and the allowed methods to GET.

Add and configure a Database connector endpoint
5. Add a Database connector to the process section of the flow.

46

6. In the Database Properties view, change the display name to American DB Request.
7. Click the Add button next to connector configuration.
8. In the Choose Global Type dialog box, select Connector Configuration > MySQL Configuration
and click OK.
9. In the Global Element Properties dialog box, set the name to Training_MySQL_Configuration.
10. Set the server, port, user, password, and database values to the values listed in the course
snippets file for the MySQL database.
11. Click the Add File button next to the MySQL driver required dependency.

12. Browse to the mysql-connector-java-{version}-bin.jar file located in the
APEssentials3.7_studentFiles_{date}/jars folder and click Open.

47

13. Back in the Global Element Properties dialog box, click the Test Connection button; you should
get a successful test dialog box.

Note: If you are not using the MuleSoft Training server image (the OVA) and your database
connectivity test fails, make sure you are not behind a firewall restricting access to port 3306. If
you cannot access port 3306, use the setup instructions to install and set up VirtualBox to use
the MuleSoft Training server image.
14. Click OK to close the dialog box.
15. Click OK to close the Global Element Properties dialog box.

Write a query to return all flights
16. In the Properties view for the database endpoint, select the Select operation.
17. In the parameterized query text box, write a query to select all records from the flights database.

SELECT	
  *	
  	
  
FROM	
  flights	
  

Test the application
18. Save the file to redeploy the application.
19. Make a request to http://localhost:8081/american; you should get some garbled plain text
displayed or contained in a download file, which is the tool’s best representation of an ArrayList.

48

Debug the application
20. Add a Logger component after the Database connector endpoint and add a breakpoint to it.
21. Save the file, debug the application, and make a request to http://localhost:8081/american.
22. In the Mule Debugger view, drill-down and look at the data contained in the payload.
23. Find the name of the field for the flight destination.

24. Stop the Mule Debugger.

Display the return data
25. Set the Logger message to #[payload].
26. Add an Object to String transformer before the Logger component.

49

27. Save and run the application.
28. Make another request to http://localhost:8081/american; you should see the query results
displayed.

29. Look at the console; you should also see the query results there.

Note: To set the width of the console, select Anypoint Studio > Preferences > Run/Debug >
Console and select Fixed width console and set a maximum character width.

Set a flow variable to hold the value of a query parameter
30. Select the Set Destination transformer in the getUnitedFlightsFlow and from the main menu,
select Edit > Copy (or press Cmd+C).

50

31. Click in the process section of the getAmericanFlightsFlow and from the main menu, select Edit
> paste (or press Cmd+V); you should see a copy of the transformer added to the flow.
32. Move the transformer before the American DB Request endpoint.
33. In the Variable Properties view, change the display name to Set Destination and review the
expression.

Modify the query to use a dynamic destination
34. In the Properties view for the Database connector endpoint, modify the query to use the
destination flow variable.

SELECT	
  *	
  	
  
FROM	
  flights	
  
WHERE	
  toAirport	
  =	
  #[flowVars.destination]	
  
35. Save to redeploy the application and make another request to http://localhost:8081/american;
you should now only see flights to SFO.

36. Make another request to http://localhost:8081/american?code=CLE; you should now see flights
to CLE.

51

Walkthrough 4-2: Connect to a file (CSV)
In this walkthrough, you will load data from a local CSV file. You will:
•

Add and configure a File connector endpoint to watch an input directory, read the contents of
any added files, and then rename the files and move them to an output folder.

•

Add a CSV file to the input directory and watch it renamed and moved.

•

Restrict the type of file read.

•

Use the File to String transformer to return the results as a string.

Create new directories
1. Return to apessentials.xml.
2. Right-click the src/main/resources folder in the Package Explorer and select New > Folder.

3. Set the folder name to input and click Finish.
4. Create a second folder called output.

52

Add and configure a File connector endpoint
5. Drag a File connector from the palette and drop it in the canvas to create a new flow.
6. Rename the flow to getCSVAccountsFlow.

7. In the File Properties view, set the path to src/main/resources/input.
8. Set the move to directory to src/main/resources/output.

9. Look at the default polling information; the endpoint checks for incoming messages every 1000
milliseconds and sets a minimum of 500 milliseconds a file must wait before it is processed.

Display the file contents
10. Add a File to String transformer to the process section of the flow.
11. Add a Logger after the transformer.

53

Run the application
12. Save the file to redeploy the application.
13. Leave the application running.

Add a CSV file to the input directory
14. Right-click the apessentials project in the Package Explore and select Show In > System
Explorer.
15. Navigate to the src/main/resources folder.
16. In another window, navigate to the student files folder for the course:
APEssentials3.7_studentFiles_{date}.
17. Locate the resources/accounts.csv file.
18. Make a copy of this file and put it in the src/main/resources folder of the apessentials project.

Test the application
19. Drag the CSV into the input folder; you should see it almost immediately moved to the output
folder.

20. Drag it back into the input folder; it will be read again and then moved to the output folder.
21. Leave this folder open.

Debug the application
22. Return to apessentials.xml.
23. Add a breakpoint to the Logger.
24. Debug the application.

54

25. Move the accounts.csv file from the output folder back to the input folder.
Note: You can do this in your operating system window or in Anypoint Studio. If you use
Anypoint Studio, you will need to right-click on the project and select Refresh to see the file.
26. Wait until code execution stops at the Logger.
27. Drill-down and look at the payload.
28. Look at the inbound message properties and locate the original filename.

29. Click the Resume button in the Mule Debugger view.
30. Stop the debugger.

Restrict the type of file read
31. Open the Properties view for the File endpoint.
32. Click the Add button next to file name regex filter.
33. In the File Name Regex Filter dialog box, set the pattern to .*csv and uncheck case sensitive.

34. Click Finish.

55

Rename the file
35. Set the move to pattern to append .backup to the original filename.

#[message.inboundProperties.originalFilename].backup	
  

Test the application
36. Save the file and run the application.
37. Move the accounts.csv file from the output folder back to the input folder; you should see it
appear in the output folder with its new name.

38. Look at the console; you should see the contents of the file displayed.

39. Move the accounts.csv.backup file from the output folder back to the input folder; it should not
be processed and moved to the output folder.

56

Walkthrough 4-3: Connect to a JMS queue (ActiveMQ)
In this walkthrough, you will read and write messages from a JMS topic. You will:
•

Create a flow accessible at http://localhost:8081/jms.

•

Add and configure an ActiveMQ connector.

•

Use a JMS endpoint to retrieve messages from a JMS topic.

•

Add messages to the topic using a web form.

•

Use a JMS endpoint to send messages to a JMS topic.

Create a JMS inbound-endpoint
1. Return to apessentials.xml.
2. Drag out a JMS connector and drop it at the bottom of the canvas to create a new flow.
3. Give the flow a new name of getTopicMessagesFlow.

4. In the JMS Properties view, select topic and set it to apessentials.
5. Click the Add button next to connector configuration.

57

6. In the Choose Global Type dialog box, select Connector Configuration > JMS > Active MQ and
click OK.

7. In the Global Element Properties dialog box, change the broker URL to the JMS ActiveMQ
Broker URL listed in the course snippets file.
8. Set the Specification to v1.1.

9. Click the Advanced tab and take a look at the various settings.
10. Click OK.
11. Click the Apply Changes button in the Properties view.

58

12. If you see An Attribute ‘action’ is required warning, ignore it.
Note: This is a bug in the Anypoint Studio January 2015 release.

Add the ActiveMQ library
13. In the Package Explorer, right-click apessentials and select New > Folder.
14. In the New Folder dialog box, set the folder name to lib and click Finish.
15. Locate activemq-all-{version}.jar file located in the APEssentials3.7_studentFiles_{date}/jars
folder.
16. Copy and paste or drag the JAR file into your lib folder.
17. Right-click the file in the Package Explorer and select Build Path > Add to Build Path; you
should now see it under Referenced Libraries.

Note: Adding activemq-all.jar can create conflicts with other dependencies in projects, so it is
recommended that you only add only the jar files you need in relation to what you need
ActiveMQ for. For more details, see the documentation at
http://www.mulesoft.org/documentation/display/current/ActiveMQ+Integration.

59

Test the application and receive messages
18. Add a Logger to the process section of the flow and set its message to #[payload].
19. Save the file and run the application.
20. Make a request to the JMS form URL listed in the course snippets file.
21. In the form, enter your name and a message and click Send.

22. Return to the console in Anypoint Studio; you should see your message along with those from
your classmates – but you don’t see the names of the people who sent the messages.

Debug the application
23. Add a breakpoint to the Logger.
24. Debug the application.
25. Make another request to the JMS form URL and submit another message.
26. In the Mule Debugger view, look at the payload and inbound message properties.

27. Stop the Mule Debugger.
60

Display names with the messages
28. In the Logger Properties view, change the message to use an expression to display the name
and message.

#[message.inboundProperties.name	
  +	
  ":	
  "	
  +	
  payload]	
  

Test the application
29. Save the file and run the application.
30. Return to the message form and submit a new message.
31. Look at the console; you should now see names along with messages.

Create a JMS outbound-endpoint
32. Drag out another HTTP connector and drop it in the canvas to create a new flow.
33. Give the flow a new name of postTopicMessageFlow.
34. In the HTTP Properties view, set the connector configuration to the existing
HTTP_Listener_Configuration.
35. Set the path to /jms and the allowed methods to GET.
36. Drag out another JMS connector and drop it into the process section of the flow.

37. In the JMS Properties view, select topic and set it to apessentials.
38. Set the connector configuration to the existing Active_MQ.
39. If you see An Attribute ‘action’ is required warning, ignore it.

61

Set a message
40. Add a Set Payload transformer between the HTTP and JMS connectors.

41. In the Set Payload Properties view, change the display name to Set Message and set the value
to a message query parameter.

42. Add a breakpoint to the Set Payload transformer.
43. Add a Property transformer after the Set Payload transformer.
44. In the Properties view, change the display name to Set Name.

62

45. Select Set Property and set the name to name and the value to your name.
Note: You can set this to a query parameter instead if you prefer.

Test the application and post messages
46. Save to redeploy the application and make a request to
http://localhost:8081/jms?message=Hello.
47. Look at the console; you should see your name and message displayed – along with those of
your classmates.

63

Walkthrough 4-4: Connect to a SaaS application (Salesforce)
In this walkthrough, you will retrieve account records from Salesforce. You will:
•

Browse Salesforce data on http://salesforce.com.

•

Create a flow accessible at http://localhost:8081/sfdc.

•

Add a Salesforce connector endpoint to retrieve accounts for a specific postal code.

•

Use the Query Builder to write a query.

•

Use the Object to JSON transformer to return the results as a string.

Note: To complete this walkthrough, you need a Salesforce Developer account. Instructions for
creating a Salesforce developer account and getting a security token are included in the Setup
instructions at the beginning of this student manual.

Look at existing Salesforce account data
1. In a browser, go to http://salesforce.com and log in with your Salesforce Developer account.
2. Click the Accounts link in the main menu bar.
3. In the view drop-down, select All Accounts and click the Go button.

64

4. Look at the existing account data; a Salesforce Developer account is populated with some
sample data.

5. Notice that countries and postal codes are not displayed by default.
6. Click the Create New View link next to the drop-down displaying All Accounts.
7. Set the view name to All Accounts with Postal Code.
8. Locate the Select Fields to Display section.
9. Select Billing Zip/Postal Code as the available field and click the Add button.
10. Add the Billing Country and Account Number fields.
11. Use the Up and Down buttons to order the fields as you prefer.
12. Click the Save button; you should now see all the accounts with postal codes and countries.

Create a new project and flow
13. Return to apessentials.xml in Anypoint Studio.
14. Drag out an HTTP connector and drop it above the getCSVAccountsFlow to create a new flow.
15. Give the flow a new name of getSFDCAccountsFlow.
16. In the HTTP Properties view, set the connector configuration to the existing
HTTP_Listener_Configuration.
17. Set the path to /sfdc and the allowed methods to GET.
65

Add a Salesforce connector endpoint
18. Drag out a Salesforce connector and drop it in the process section of the flow.
19. In the Select a version dialog box, click Use newest.

20. Examine the flow.

Configure the Salesforce connector
21. In the Salesforce Properties view, click the Add button next to Connector Configuration.
22. In the Choose Global Type dialog box, select Connector Configuration > Salesforce: Basic
authentication and click OK.

66

23. In the Global Element Properties dialog box, enter your email username, password, and security
token.
Note: Instructions for creating a Salesforce Developer account and getting a security token are
included in the Setup instructions at the beginning of this student manual.

24. Click the Test Connection button; you will get a Test Connection dialog box letting you know if
the connection succeeds or fails.

25. Click OK to close the Test connection dialog box.
26. If your test connection failed, fix it; do not proceed until it is working.
Note: If it failed, check to see if you have any extra whitespace in your entries.
27. Click OK to close the Global Elements Properties dialog box.

67

Write the query
28. In the Salesforce Properties view, select an operation of Query.
29. Click the Query Builder button.

30. In the Query Builder dialog box, select a type of Account.
31. Select fields BillingCity, BillingCountry, BillingPostalCode, BillingState, BillingStreet, and Name.

32. Click OK.

68

33. Examine the generated query.

Test the application
34. Save the file to redeploy the application.
Note: If you get a SAXParseException, stop the Mule runtime and run the application again. If
you still get an exception, close and reopen the project. If that does not work, restart Anypoint
Studio.
35. Make a request to http://localhost:8081/sfdc; you should get an error in the console stating that
the transformer needs a valid endpoint.

Debug the application
36. Add a Logger component after the Salesforce endpoint.
37. Set the Logger message to #[payload].
38. Add a breakpoint to the Logger.
39. Save the file and debug the application.
40. Make another request to http://localhost:8081/sfdc.
41. Step to the Logger and drill-down into the payload variable.
42. Click the Evaluate Mule Expression button in the Mule Debugger view.

43. Enter the following expression and press the Enter key.

#[payload.next()]	
  

69

44. Expand the results; you should see the account data for the first account.

45. Click anywhere outside the expression window to close it.
46. Stop the Mule Debugger.

Display the return data
47. Add an Object to JSON transformer before the Logger component.

48. Save the file and run the application.
49. Make another request to http://localhost:8081/sfdc; you should see the Salesforce accounts
displayed.

70

Modify the query
50. In the Salesforce Properties view, click the Query Builder button.
51. In the Query Builder dialog box, click the Add Filter button.
52. Create a filter for BillingPostalCode equal to one of the postal codes (like 27215) in your
Salesforce account data.

53. Click OK.
54. Examine the generated query.

71

Test the application
55. Save the file to redeploy the application.
56. Make another request to http://localhost:8081/sfdc; you should only the accounts with the
specified postal code displayed.

72

Walkthrough 4-5: Find and install not-in-the-box connectors
In this walkthrough, you will learn how to add a new connector to Anypoint Studio. You will:
•

Browse the Anypoint Exchange.

•

Add a new connector to Anypoint Studio.

Browse the Anypoint Exchange from Anypoint Studio
1. In Anypoint Studio, click the Open Exchange button; the Anypoint Exchange should open in a
new window.

2. Click the Connectors button.

73

3. Browse the connectors, exploring the different levels and categories.

4. Locate the Google Contacts connector (or any other connector you are interested in).
5. Click the View details button and browse the connector’s documentation.

74

Install the connector
6. In the Anypoint Exchange, click the connector’s Install button.
7. Wait until an Install dialog box appears in Anypoint Studio.

Note: If you do not see the connector listed, resize the Install dialog box.
Note: You can also install connector’s directly from Anypoint Studio. From the main menu bar,
select Help > Install New Software. In the Install dialog box, click the Work with drop-down
button and select Anypoint Connectors Update Site. Drill-down into Community and select the
Google Contacts Connector (or some other connector).
8. On the Install Details page, click Next.
9. On the Review Licenses page, select the I accept the terms radio button.
10. Click Finish; the software will be installed and then you will get a message to restart Anypoint
Studio.
11. In the Software Updates dialog box, click Yes to restart Anypoint Studio.
12. After Anypoint Studio restarts, locate the new connector in the Connectors section of the
palette.

75

Module 5: Transforming Data

In this module, you will learn:
•

About the different types of transformers.

•

To use the DataWeave Transform Message component.

•

To write DataWeave expressions for basic and complex XML, JSON, and Java transformations.

•

To use DataWeave with data sources that have associated metadata.

•

To add custom metadata to data sources.

76

Walkthrough 5-1: Load external content into a message
In this walkthrough, you will add an HTML form to your application that will eventually serve as a front
end for the MUA integration application. You will:
•

Create a new flow that receives GET requests at http://localhost:8081/flights.

•

Use the Parse Template transformer to load the content of an HTML file into a flow.

•

Examine the HTML code and determine what data it sends where

Add an HTML file to the project
1. On your computer, navigate to the student files folder for the course,
APEssentials3.7_studentFiles_{date}.
2. Copy and paste (or drag) the resources/FlightFinder.html file into your project’s
src/main/resources folder.

Note: You will examine the HTML code soon – after you load the form and see what it looks like.

Create a flow
3. Return to apessentials.xml.
4. Drag out another HTTP connector to create a new flow at the top of the canvas and name it
getFlightFormFlow.
5. In the HTTP Properties view, set the connector configuration to the existing
HTTP_Listener_Configuration.
6. Set the path to /flights and set the allowed methods to GET.

77

Set the payload to HTML and JavaScript
7. Add a Parse Template transformer to the process section of the flow.

8. In the Properties view for the transformer, set the location to FlightFinder.html.

Debug the application
9. Add a breakpoint to the Parse Template transformer.
10. Add a Logger component after the transformer.
11. Save the file and debug the application.
12. In a browser, make a request to http://localhost:8081/flights.
13. Step through the flow and watch the value of the payload change.

78

14. Step through the rest of the flow and then return to the browser window; you should see the
HTML form.

15. Click the Find Flights button; what happens?

Review the HTML form code
16. Open FlightFinder.html in Anypoint Studio.
17. Locate the form at the bottom and find the names of the select boxes and their option values.

18. Locate to where the form data is posted.

19. Locate in what format the data is that is posted.

79

Walkthrough 5-2: Write your first DataWeave transformation
In this walkthrough, you will work with the data posted from the HTML form. You will:
•

Create a new flow that receives POST requests at http://localhost:8081/flights.

•

Use the DataWeave Transform Message component.

•

Add sample data and use live preview.

•

Transform the form data from JSON to a Java object.

Create a new flow
1. Return to apessentials.xml.
2. Drag out another HTTP connector to create a new flow and name it getFlightsFlow
3. In the HTTP Properties view, set the connector configuration to the existing
HTTP_Listener_Configuration.
4. Set the path to /flights (the same as the form flow) and set the allowed methods to POST.

Look at the data posted from the form
5. Add a Logger to the flow and add a breakpoint to it.
6. Save the file to redeploy the application in debug mode.
7. Make another request to http://localhost:8081/flights.
8. Step through or remove the breakpoints in the getFlightsFormFlow to get to the form in the
browser window.
9. Click the Find Flights button.

80

10. Look at the Mule Debugger view; you should see the return data is a BufferInputStream.
11. Look at the inbound properties; you should see the content-type is set to application/json.

Add a DataWeave Transform Message component
12. Add a DataWeave Transform Message component before the Logger.

13. In the Transform Message Properties view, look at the Input, Transform, and Output sections.
14. In the Transform section, locate the drop-down menu at the top of the view that sets the output
type; it should be set to Payload.
15. Beneath it, locate the directive that sets the output to application/java.
16. Delete the existing DataWeave expression (the curly braces) and set it to payload.

Debug the application
17. Add a breakpoint to the Transform Message component (if it does not have one).
18. Save the file to redeploy the application in debug mode.
19. Make a request to http://localhost:8081/flights and submit the form again.

81

20. Step to the Logger in the getFlightsFlow; you should see the form data is now a
LinkedHashMap.

21. Click the Resume button.

Add sample data and preview
22. In the Input section of the Transform Message Properties view, click Payload: Unknown.
23. Click the Sample Data button.

24. In the Sample data format dialog box, select JSON and click OK.

25. In the new payload window that is created in the Input section, replace the sample JSON data
with {"destination":"SFO","airline":"united"}.
Note: You can copy this value from the course snippets.txt file.

82

26. Click the Preview tab in the Output section; you should see sample output of type Java.

Change the output type
27. In the Transform section, change the output type from application/java to application/xml.
28. Look at the Preview tab; you should get an error.

29. Change the output type to application/json; in the Preview tab, you should see sample JSON
output.

Debug the application
13. Save the file to redeploy the application in debug mode.
14. Make a request to http://localhost:8081/flights and submit the form again.

83

15. Step to the Logger in the getFlightsFlow; you should see the form data is now of type
WeaveOutputHandler.

16. Click the Resume button.
17. Stop the Mule runtime.

Change the output type
18. In the Transform section, change the output type from application/json back to application/java.
19. Save the file.

Examine the code
20. In the Package Explorer, locate the sample data in src/test/resources.

21. Switch to the Configuration XML view.
22. Locate the DataWeave code.
23. Switch back to the Message Flow view.

84

Walkthrough 5-3: Transform basic Java, JSON, and XML data
structures
In this walkthrough, you will continue to work with the data posted from the HTML form. You will:
•

Write transformations to store data in multiple outputs as different types of data.

•

Create a second transformation to store the destination in a flow variable.

•

Create a third transformation to output data as JSON.

•

Create a fourth transformation to output data as XML.

Create a second transformation to store destination in a flow variable
1. Return to getFlightsFlow in apessentials.xml.
2. Return to the Properties view for the Transform Message component.
3. In the Transform section, click the Add New Transformation button in the lower-right corner.

4. In the new myVar tabbed window that appears in the Transform section, make sure the Output
is set to Flow Variable.
5. Set the name to destination.
6. Set the DataWeave expression to payload.destination.

85

7. Look at the preview in the Output section; you should the string SFO.

Debug the application
8. Save the file and debug the application.
9. Make a request to http://localhost:8081/flights, select LAX and Delta, and submit the form again.
10. Step to the Logger and click the Variables tab; you should see now see your flow variable in
addition to the transformed payload.

11. Click the Resume button.
Note: You will continue working with this flow in a later walkthrough. You will add functionality to
get the requested flight data from the other flows and return it back to the form.

Create a third transformation to output data as JSON
12. In the Transform Message Properties view, click the Add New Transformation button.
13. In the new window, leave the Output set to Flow Variable.
14. Set the name to json.
15. Set the DataWeave expression to payload.
16. Change the output type to application/json.

86

17. Look at the preview in the Output section.

18. Change the DataWeave expression to data: payload.

19. Change the DataWeave expression to data: {}.

20. Add a field called hub and set it to “MUA”.

87

21. Add a field called code and set it to the destination property of the payload.
22. Add a field called airline and set it to the airline property of the payload.

Create a fourth transformation to output data as XML
23. Click the Add New Transformation button.
24. In the new window, leave the Output set to Flow Variable.
25. Set the name to xml.
26. Set the DataWeave expression to payload.
27. Change the output type to application/xml; you should get an error message in the preview tab.

28. Change the DataWeave expression to data: payload.

29. Click the json tab and copy the DataWeave expression.
88

30. Click the xml tab and replace the DataWeave expression with the one you just copied.
31. Modify the expression so the code and airline properties are child elements of a new element
called flight.

32. Modify the expression so the airline is an attribute of the flight element.

33. Change the name of the component to Set payload and destination flowVar.

89

Debug the application
34. Save the file to redeploy the application in debug mode.
35. Make a request to http://localhost:8081/flights and submit the form again.
36. Step to the Logger and click the Variables tab; you should now see three flow variables.

37. Stop the Debugger.
Note: The json and xml flow variables were created for learning purposes. If you want, you can
delete them from the DataWeave transformer.

90

Walkthrough 5-4: Transform complex data structures
In this walkthrough, you will work with static flight data not retrieved using a connector. You will:
•

Create a new flow that receives GET requests at http://localhost:8081/static.

•

Transform a JSON array of objects to Java, JSON, and XML.

•

Explicitly set the MIME type of the data to be transformed.

•

Transform XML with repeated elements to XML and JSON.
Note: You will work with CSV data in the Processing Records module.

Create a new flow
1. Return to apessentials.xml.
2. Drag out another HTTP connector to create a new flow and name it transformStaticFlightsFlow
3. In the HTTP Properties view, set the connector configuration to the existing
HTTP_Listener_Configuration.
4. Set the path to /static and set the allowed methods to GET.

Add static JSON payload data
5. Add a Set Payload transformer to the flow.
6. Return to the course snippets.txt file and copy the value for the Example flights JSON.

91

7. In the Set Payload Properties view, paste the copied value into the value field.

Transform the payload to Java
8. Add a DataWeave Transform Message component and a Logger to the flow.

9. In the Transform Message Properties view, set the DataWeave expression to payload.
10. Look at the Preview tab in the Output section; you should not see any preview of the data.

Add sample data
11. In the Input section, click Payload: Unknown.
12. Click the Sample Data button.
13. In the Sample data format dialog box, select JSON and click OK.
14. In the new payload tab, replace the sample JSON with the JSON you used in the Set Payload
transformer.

92

15. Look at the Preview tab in the Output section; you should now see a preview of the data and
there should be three LinkedHashMap objects.

Debug the application
16. Add a breakpoint to the Transform Message component.
17. Save the file and debug the application.
18. Make a request to http://localhost:8081/static.
19. Step to the Transform Message component; you should see the payload is of type String.

20. Step to the Logger; you should see the payload is still of type String.

21. Click the Resume button.

93

Set the payload MIME type
22. In the Set Payload Properties view, set the MIME type to application/json.

23. Apply the changes and wait for the application to redeploy.
24. Make a request to http://localhost:8081/static.
25. Step to the Logger; the payload should now be of type ArrayList.

26. Click the Resume button; you should get a file download or garbled data depending upon if you
are using a browser or some other tool to make your request.

Return values for the first object in the collection
27. Change the DataWeave expression to payload[0]; in the Preview tab, you should see one
LinkedHashMap object.

94

28. Change the DataWeave expression to payload[0].price; in the Preview tab, you should get 400,
the first price value.
29. Change the DataWeave expression to payload[0].*price; in the Preview tab, you should see an
ArrayList with one integer value of 400 – the first price value.

Return collections of values
30. Change the DataWeave expression to return a collection of all the prices.

payload.*price	
  or	
  payload.price	
  
31. Look at the Preview tab; you should see an ArrayList with three values.

32. Change the DataWeave expression to return a collection of prices and available seats.

[payload.price,	
  payload.availableSeats]	
  
33. Look at the Preview tab; you should see an ArrayList with two ArrayLists.

95

Use the map operator to return object collections with different data structures
34. Change the DataWeave expression to payload map $, in the Preview tab, you should see three
Java objects again.

35. Change the DataWeave expression to set a property called flight for each object that is equal to
its index value in the collection.

36. Change the DataWeave expression to create a property called dest for each object that is equal
to the value of the destination field in the payload collection.

96

37. Change the DataWeave expression to dynamically add each of the properties present on the
payload objects.

38. Change the DataWeave expression so the name of each object is flight+index and you get
flight0, flight1, and flight2.

Change the output to JSON and test the application
39. Change the DataWeave expression output type from application/java to application/json.
40. Save the file and run the application.

97

41. Make a request to http://localhost:8081/static; you should see the correct JSON returned.

Change the expression to output valid XML and test the application
42. Change the DataWeave expression output type from application/json to application/xml; you
should get an error in the Preview tab.
43. Change the DataWeave expression to create a root node called flights; you should still get an
error in the Preview tab.
44. Change the expression to map each item in the input array to an XML element.

	
  flights:	
  {(payload	
  map	
  {	
  
	
  

'flight$$':$	
  

	
  

}	
  

)}	
  
98

45. Save the file and run the application.
46. Make a request to http://localhost:8081/static; you should see the XML returned.

47. Save the file and run the application.
48. Make a request to http://localhost:8081/static; you should see the XML returned.

Add static XML payload data
49. Return to the course snippets.txt file and copy the value for the Example flights XML.
50. In the Set Payload Properties view, paste the copied value into the value field.

99

51. Change the MIME type to application/xml.

52. In the Input section of the Transform Message Properties view, click the x on the payload tab to
delete the src/test/resources/sample_data/json_1.json file.
53. Click Payload: Unknown and then the Sample Data button.
54. In the Sample data format dialog box, select XML and click OK; a new sample data file
empty.xml should be created.

55. In the Transform Message Properties view, replace the sample payload data with the Example
flights XML you copied.

Change the return structure of the XML
56. Look at the Preview tab; you should see all the flights are children of the flight0 element.

100

57. Change the DataWeave expression to loop over the payload.listAllFlightsResponse element;
you should see the flights are now correctly transformed.

58. Change the DataWeave expression to loop over the payload.listAllFlightsResponse.return
element.

59. Change the DataWeave expression use * to loop over the XML repeated return elements.

101

60. Change the DataWeave expression to return XML with repeated flight elements.

flights:	
  {(payload.listAllFlightsResponse.*return	
  map	
  {	
  
	
  

flight:	
  $	
  

	
  	
  }	
  	
  
)}	
  
61. Change the DataWeave expression to return flight elements with dest and price elements that
map to the corresponding destination and price input values.

Change the output structure to JSON
62. Change the transform output type from XML to JSON.

Note: This is invalid JSON and should result in an error.

102

63. Remove the {( and )} around the payload map expression.

flights:	
  payload.listAllFlightsResponse.*return	
  map	
  {	
  
	
  

flight:	
  {	
  

	
  

	
  	
  

dest:	
  $.destination,	
  

	
  

	
  	
  

price:	
  $.price	
  

	
  

}	
  

}	
  
64. Change the DataWeave expression to return an array of objects without the flights and flight
properties.

payload.listAllFlightsResponse.*return	
  map	
  {	
  
	
  

dest:	
  $.destination,	
  

	
  

price:	
  $.price	
  

}	
  
65. Save the file and run the application.
66. Make a request to http://localhost:8081/static and look at the JSON structure returned.

103

Walkthrough 5-5: Use DataWeave operators
In this walkthrough, you will continue to work with the static flight data from the last exercise. You will:
•

Format strings, dates, and numbers.

•

Convert data types.

•

Replace data values using pattern matching.

•

Order data, filter data, and remove duplicate data.

•

Define and use custom data types.

•

Transform objects to POJOs.

Format a string
1. Return to transformStaticFlightsFlow in apessentials.xml.
2. Change the DataWeave expression to return objects with a property called plane equal to the
value of the input planeType values.
3. Use the upper operator to return the value in uppercase.

plane:	
  upper	
  $.planeType	
  
4. Look at the Preview tab; you should see the uppercase plane fields.
5. Look at the data type of the prices; you should see that they are strings (surrounded by
quotation marks).

104

Convert data types
6. Change the DataWeave expression to use the as operator to return the prices as numbers (not
surrounded by quotation marks) instead of strings.

7. Add a departureDate field to the return object.

payload.listAllFlightsResponse.*return	
  map	
  {	
  
	
  

dest:	
  $.destination,	
  

	
  

price:	
  $.price	
  as	
  :number,	
  

	
  

plane:	
  upper	
  $.planeType	
  

	
  

departureDate:	
  $.departureDate	
  

}	
  	
  
8. Change the transform output type from json to java.

%output	
  application/java	
  
9. Look at the Preview tab; you should see the departureDate property is a String.

105

10. Change the DataWeave expression to use the as operator to convert departureDate to a date
object.
11. Look at the Preview tab; you should get an error message.

12. Look at the format of the dates in the sample data in the payload tab in the Input section.

13. Use the format operator to specify the pattern of the input date strings.

departureDate:	
  $.departureDate	
  as	
  :date	
  {format:	
  "yyyy/MM/dd"}	
  
Note: If you are not a Java programmer, you may want to look at the Java documentation for the
DateTimeFormatter class to review documentation on pattern letters. See:
https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html.
14. Look at the Preview tab; you should see departureDate is now a Date object.

106

Format a date
15. Use the as operator to convert the dates to strings, which can then be formatted.
departureDate:	
  $.departureDate	
  as	
  :date	
  {format:	
  "yyyy/MM/dd"}	
  as	
  :string	
  
16. Look at the Preview tab; the departureDate is again a String.

17. Use the format operator with any pattern letters and characters to format the date strings.

departureDate:	
  $.departureDate	
  as	
  :date	
  {format:	
  "yyyy/MM/dd"}	
  
as	
  :string	
  {format:	
  "MMM	
  dd,	
  yyyy"}	
  
18. Look at the Preview tab; the departureDate properties should now be formatted.

19. Change the transform output from java to json.

%output	
  application/json	
  
20. Save the file and run the application.
21. Make a request to http://localhost:8081/static; you should see the formatted dates.

107

Format a number
22. Use the format operator in the DataWeave expression to format the prices with two decimal
places.

price:	
  $.price	
  as	
  :number	
  {format:	
  "###.##"},	
  
23. Look at the Preview tab; the prices should be formatted.

Note: There is a bug in Anypoint Studio 5.2.1 (whose live preview uses Mule runtime 3.7.1) and
Mule runtime 3.7.1 and the numbers are not formatted correctly.
24. Save the file and run the application.
25. Make a request to http://localhost:8081/static; you should see the formatted prices (but may
not).
26. Change the DataWeave expression to format the prices to zero decimal places.

price:	
  $.price	
  as	
  :number	
  {format:	
  "###"},	
  
27. Look at the Preview tab; you should (but may not) see the second price is now 200 instead of
199.99.

Define a custom data type
28. In the header section of the Transform section, define a custom data type called currency.

29. Select the data coercion and formatting expression for the price in the DataWeave expression
and move it to the currency data type definition.

%type	
  currency	
  =	
  :number	
  {format:	
  "###"}	
  

108

30. In the DataWeave expression, set the price to be of type currency.

price:	
  $.price	
  as	
  :currency,	
  
31. Look at the Preview tab; the prices should still be formatted.
Note: There is a bug in Mule runtime 3.7.1 and the numbers are not formatted correctly.

Replace data values
32. Use the replace operator in the DataWeave expression to replace the string Boing with Boeing.

plane:	
  upper	
  $.planeType	
  replace	
  /(Boing)/	
  with	
  "Boeing",	
  
33. Look at the Preview tab; Boeing should be spelled correctly.

Order data
34. In the Preview tab, look at the flight prices; the flights should not be ordered by price.
35. Change the DataWeave expression to use the orderBy operator to order the objects by price.

payload.listAllFlightsResponse.*return	
  map	
  {	
  
	
  

…	
  

}	
  orderBy	
  $.price	
  	
  

109

36. Look at the Preview tab or run the application; the flights should now be ordered by price.

37. Look at the PDX flights; they should not be ordered by departureDate.
38. Change the DataWeave expression to first sort by departureDate and then by price.

payload.listAllFlightsResponse.*return	
  map	
  {	
  
	
  

…	
  

}	
  orderBy	
  $.departureDate	
  orderBy	
  $.price	
  	
  
39. Look at the Preview tab or run the application; the flights should now be ordered by price and
flights of the same price should be sorted by departureDate.

Remove duplicate data
40. Use the distinctBy operator in the DataWeave expression to remove any duplicate objects.

payload.listAllFlightsResponse.*return	
  map	
  {	
  
	
  

…	
  

}	
  orderBy	
  $.departureDate	
  orderBy	
  $.price	
  distinctBy	
  $	
  

110

41. Look at the Preview tab; you should now see only four flights instead of five.

Note: If you still get five flights, remove the currency type coercion (or replace it with the
currency expression) from the price field. This is a bug in Mule runtime 3.7.1.
42. Add an availableSeats field that is equal to the emptySeats field and coerce it to a number.

availableSeats:	
  $.emptySeats	
  as	
  :number	
  
43. Look at the Preview tab; you should see five flights again.

Add Java classes file to the project
44. On your computer, navigate to the java folder in the student files folder for the course:
APEssentials3.7_studentFiles_{date}/java.
45. Copy and paste (or drag) the com.mulesoft.training folder into your Anypoint Studio project’s
src/main/java folder.
46. Open the Flight.java class and look at the names of the properties.

111

Transform objects to POJOs
47. Return to transformStaticFlightsFlow in apessentials.xml.
48. Change the transformation output from json to java.

%output	
  application/java	
  
49. Look at the Preview tab and see that LinkedHashMap objects are created.

50. In the header section of the Transform section, define a custom data type called flight that is a
com.mulesoft.training.Flight Java object.

%type	
  flight	
  =	
  :object	
  {class:	
  "com.mulesoft.training.Flight"}	
  
51. In the DataWeave expression, set the map objects to be of type flight.

payload.listAllFlightsResponse.*return	
  map	
  {	
  
	
  

…	
  

}	
  as	
  :flight	
  orderBy	
  $.departureDate	
  orderBy	
  $.price	
  distinctBy	
  $	
  
52. In the Transform section, look at the warning you get: Key ‘dest’ not found.

53. Change the name of the dest key to destination.

destination:	
  $.destination,	
  
54. Change the name of the plane key to planeType.

planeType:	
  $.planeType,	
  
112

55. Look at the Preview tab; the objects should now be of type Flight.

56. Save the file and debug the application.
57. Make a request to http://localhost:8081/static.
58. Step to the Logger and drill-down into the payload; the objects should be of type Flight.

59. Stop the debugger.

Filter data
60. Return to transformStaticFlightsFlow in apessentials.xml.
61. In the Preview tab, look at the values of the availableSeats properties.
62. Add a filter to the DataWeave expression that removes any objects that have availableSeats
equal to 0.

payload.listAllFlightsResponse.*return	
  map	
  {	
  
	
  

…	
  

113

}	
  as	
  :flight	
  orderBy	
  $.departureDate	
  orderBy	
  $.price	
  distinctBy	
  $	
  	
  	
  	
  
	
  	
  	
  	
  	
  filter	
  ($.availableSeats	
  !=0)	
  
63. Look at the Preview tab; you should no longer see the flight that had no seats.

114

Walkthrough 5-6: Transform data sources that have associated
metadata
In this walkthrough, you will work with the American and Delta flight data. You will:
•

Use DataWeave to transform the American flight data from a collection of Java objects to one
with a different data structure.

•

Use DataWeave to transform the Delta flight data from XML to a collection of Java objects.

Add a DataWeave Transform Message component
1. Locate getAmericanFlightsFlow in apessentials.xml.
2. Delete the Object to String transformer.
3. Replace it with a Transform Message component.

4. Change the name of the Transform Message component to Java to Java.

115

5. Look at the Input section of the Transform Message Properties view; the payload should
automatically be set to a List with correct properties because the Database connector
configuration is DataSense enabled by default.

Note: If the payload is not automatically set to a List, you probably need to refresh the
connector metadata. In the American DB Request Properties view, click the Output tab in the
Metadata section and see if the payload is shown to be of type List. If it is not, click the
Refresh Metadata link beneath the metadata. If this does not work, select Anypoint >
Preferences / Window > Preferences and navigate to Anypoint Studio > DataSense and make
sure Automatic DataSense metadata retrieval is selected and click OK. If that does not work, try
restarting Anypoint Studio.
6. In the Transform section, leave the output set to Payload and of type application/java.
7. Delete the existing DataWeave expression (the curly braces) and set it to payload.
8. Look at the Preview tab in the Output section; you should see the output will be the same data
type as the input but it does not have any sample values.

116

Add sample data and preview
9. In the Input section of the Transform Message Properties view, click Payload: List.
10. Click the Sample Data button.
11. In the new payload tab, replace the “????” with sample values.

12. Look at the Preview tab in the Output section; you should see sample values.

Look at the flights schema and example files
13. On your computer, navigate to the resources folder in the student files folder for the course:
APEssentials3.7_studentFiles_{date}.
14. Copy and paste (or drag) the schemas-and-examples folder into your Anypoint Studio project’s
src/main/resources folder.

117

15. Open the flights-schema.json and flights-example.json files and examine the code.

Change the output structure
16. Change the DataWeave expression to payload map { }.
17. Inside the {}, define a new property called airlineName and map it to the payload airlineName
property; be sure to use auto-completion!

18. Add additional properties with the following mappings:
•

departureDate < takeOffDate

•

destination < toAirport

•

emptySeats < seatsAvailable

•

flightCode < code1 concatenated with code2

•

origination < fromAirport

•

planeType < planeType

•

price < price

Note: You can also copy this code from the course snippets.txt file.

118

Debug the application
19. Save the file and debug the application.
20. Make a request to http://localhost:8081/american.
21. Watch the payload value and step through to the Logger.
22. Drill-down into the data for the first and second flights in the payload and look at the data types
and values; be sure to look at emptySeats.

23. Stop the Mule Debugger.

Format the data
24. In the DataWeave expression, format the price field as a number with the pattern “###.##”.

price:	
  $.price	
  as	
  :number	
  {format:	
  "###.##"}	
  
Note: You can also define and use a custom data type.

119

25. In the DataWeave expression, add logic to set the emptySeats field to a number unless it is
equal to “none” in which case set it to 0.
emptySeats:	
  $.seatsAvailable	
  as	
  :number	
  unless	
  $.seatsAvailable=="none"	
  otherwise	
  0,	
  

Debug the application
26. Save the file and debug the application.
27. Make a request to http://localhost:8081/american.
28. Watch the payload value and step through to the Logger.
29. Drill-down into the data for the first and second flights in the payload and look at the data types
and values and make sure emptySeats and price are set correctly.

30. Stop the Mule Debugger.

Review the Delta flight data
31. Locate getDeltaFlightsFlow.
32. Run the application and make a request to http://localhost:8081/delta.

120

33. Look at the names of the XML elements and the value of the planeType element.

Review at the flights schema and example files
34. Return to or open the flights-schema.json and flights-example.json files and examine the code.

Transform the XML to Java
35. Return to getDeltaFlightsFlow.
36. Delete the DOM to XML transformer.
37. Replace it with a Transform Message component.
38. Change the name of the component to XML to Java.

121

39. Look at the Input section of the XML to Java Properties view; the payload should automatically
be set to a Xml with correct properties because the Web Service
Consumer connector configuration is DataSense enabled by default.

40. In the Transform section, leave the output set to Payload and of type application/java.
41. Delete the existing DataWeave expression (the curly braces) and set it to payload.
42. In the Preview tab, look at the resulting output structure.

122

Change the output structure
43. Change the DataWeave expression to payload.listAllFlightsResponse and look at the preview.

44. Change the DataWeave expression to payload.listAllFlightsResponse.return and look at the
preview.

45. Modify the DataWeave expression to used the map operator to populate a new airline property
with the value of the airlineName property in each object; you should get a message that the
preview cannot be updated.

123

46. Change the DataWeave expression to payload.listAllFlightsResponse.*return.

47. Add additional properties with the following mappings:
•

departureDate < departureDate

•

destination > destination

•

emptySeats < emptySeats as a number

•

flightCode < code

•

origination < origin

•

planeType < planeType with the string Boing replaced with Boeing

•

price < price and format it as a number with the pattern “###.##”

Note: You can also copy this code from the course snippets.txt file.

Debug the application
48. Save the file and debug the application.
49. Make a request to http://localhost:8081/delta.
50. Watch the payload value and step through to the Logger.
51. Drill-down into the data and make sure it all mapped correctly.
52. Stop the Mule Debugger.
124

Walkthrough 5-7: Pass arguments to a SOAP web service
In this walkthrough, you will continue to work with the Delta flight data. You will:
•

Return the flights for a specific destination instead of all the flights.

•

Change the web service operation invoked to one that requires a destination as an input
argument.

•

Use DataWeave to pass an argument to a web service operation.

•

Create a variable to set the destination to a dynamic query parameter value.

Call a different web service operation
1. Return to getDeltaFlightsFlow.
2. In the Properties view for the Delta SOAP Request endpoint, change the operation to findFlight.

3. In the Transform Message Properties view, change the DataWeave expression to reference
findFlightResponse instead of listAllFlightsResponse.

payload.findFlightResponse.*return	
  map	
  {	
  

Debug the application
4. Apply the changes and debug the application.
5. Make a request to http://localhost:8081/delta.
6. Return to Anypoint Studio and step through the flow; you should get an error.

125

7. Look at the console; you should a SoapFaultException because you are calling an operation
that requires parameters but you have not passed it any.

8. Stop the debugger.

Use DataWeave to pass parameters to the web service
9. Add a Transform Message component to the left of the Delta SOAP Request endpoint.
10. Change its name to Pass Destination.

11. Look at the Pass Destination Properties view.

126

12. Set the destination to SFO and look at the preview.

Debug the application
13. Save the file and debug the application.
14. Make a request to http://localhost:8081/delta.
15. In the Mule Debugger, step though to the Logger; you should now see only the SFO flights.

16. Step through the rest of the flow.

Set a flow variable to hold the value of a query parameter
17. Select the Set Destination transformer in getUnitedFlightsFlow and from the main menu, select
Edit > Copy (or press Cmd+C/Ctrl+C).
18. Click in the process section of getDeltaFlightsFlow and from the main menu, select Edit > paste
(or press Cmd+V/Ctrl+V); you should see a copy of the transformer added to the flow.
19. Move the transformer before the Pass Destination component.

127

20. In the Variable Properties view, change the display name to Set Destination and review the
expression.

Modify the input argument to use a dynamic destination from a query parameter
21. In the Pass Destination Properties view, replace the literal of SFO with a reference to the
destination flow variable.

Debug the application
22. Save the file and redeploy the application.
23. Make a request to http://localhost:8081/delta and step through to the Logger; you should still
only see flights to SFO.
24. Make another request to http://localhost:8081/delta?code=CLE and step through to the Logger;;
you should now only see flights to CLE.

128

Walkthrough 5-8: Transform a data source to which you add
custom metadata
In this walkthrough, you will work with the United flight data. You will:
•

Add custom metadata to an HTTP Request endpoint.

•

Use DataWeave to transform the United flight data from JSON to a collection of Java objects.

Review the United flight data
1. Run the application and make a request to http://locahost:8081/united.
2. Look at the names of the object keys.

Review at the flights schema and example files
3. Open the united-flights-example.json file located in the src/main/resources/schemas-andexamples folder and examine the code.

129

4. Open the united-flights-schema.json file located in the src/main/resources/schemas-andexamples folder and examine the code.

Add a DataWeave Transform Message component
5. Locate getUnitedFlightsFlow.
6. Add a Transform Message component after the United REST Request.
7. Change its name to JSON to Java.
8. Add a Logger after the component.

9. In the Transform Message Properties view, leave the output set to Payload and of type
application/java.
10. Look at the Input section of the Transform Message Properties view; the payload is of type
unknown.

130

Add metadata to the HTTP Request endpoint
11. In the United REST Request Properties view, click the Output tab in the Metadata section; you
should see the payload is of type unknown.

12. Click the Metadata link in the left-side navigation.
13. Click the Add metadata button.

14. In the drop-down menu that appears, select Output: Payload.
15. Click the Edit button located to the right of the drop-down menu.

16. In the Define Type dialog box, select Create new type.
17. Set the type to JSON.
18. Set the type id to United_JSON.
19. In the drop-down menu, select Example.
20. Click the browse button.
21. In the Open dialog box browse to src/main/resources/schemas-and-examples/united-flightsexample.json and click Open.
131

22. In the Define Type dialog box, click Finish.

23. Look at the Output tab in the Metadata section again; you should now see the payload is of type
JSON with a flights property that is a list of objects with specific fields.

Transform the JSON to a collection of Java objects
24. Return to the JSON to Java component Properties view.
25. Look at the Input section again; the payload should now be of type Json.

132

26. Expand the flights List; you should see the the field names of each object.

27. Delete the existing DataWeave expression (the curly braces) and set it to payload.

28. Look at the Output section; the output structure should be set to a Map.

Change the output structure
29. Change the DataWeave expression to payload.flights; the output structure should now be a List
of Map objects.

133

30. Modify the DataWeave expression to use the map operator.
31. In the transformation function, set the following mappings:
•

airlineName < airlineName

•

departureDate < departureDate

•

destination > destination

•

emptySeats < emptySeats as a number

•

flightCode < code

•

origination < origin

•

planeType < planeType

•

price < price and format it as a number with the pattern “###.##”

Note: If you want, you can copy these lines of code from the Delta DataWeave expression.

Debug the application
32. Save the file and debug the application.
33. Make a request to http://localhost:8081/united.
34. Watch the payload value and step through to the Logger.
35. Drill-down into the data and make sure it all mapped correctly.
36. Stop the Mule Debugger.

134

Module 6: Refactoring Mule
Applications

In this module, you will learn:
•

To separate applications into multiple configuration files.

•

To encapsulate global elements in a separate configuration file.

•

To create and run multiple applications.

•

To create and reference flows and subflows.

•

About variable persistence through subflows and flows and across transport barriers.

135

Walkthrough 6-1: Separate applications into multiple
configuration files
In this walkthrough, you will refactor your monolithic apessentials application. You will:
•

Separate the account flows into accounts.xml.

•

Move the rest of the example flows into examples.xml.

•

Rename apessentials.xml to getFlights.xml.

Move account flows to a new configuration file
1. Right-click the apessentials project in the Package Explorer and select New > Mule
Configuration File.
2. Set the name to accounts and click Finish.

3. In accounts.xml, switch to the Configuration XML view.
4. Place some empty lines between the start and end mule tags.
5. Return to apessentials.xml and switch to the Configuration XML view.
6. Select and cut getSFDCAccountsFlow, getCSVAccountsFlow, and getBankAccountsFlow.
7. Return to accounts.xml and paste the flows inside the mule tags.
Note: If these flows are not adjacent, you will need to repeat the process several times.
136

8. Switch to the Message Flow view.

9. Save all the files by selecting File > Sale All, clicking the Save All button, or pressing
Shift+Cmd+S.

Move non-flight flows to a new configuration file
10. Right-click the apessentials project in the Package Explorer and select New > Mule
Configuration File.
11. Set the name to examples and click Finish.

12. In examples.xml, switch to the Configuration XML view.
13. Place some empty lines between the start and end mule tags.
14. Return to apessentials.xml and select and cut apessentialsFlow, getTopicMessagesFlow, and
postTopicMessageFlow.
15. Return to examples.xml and paste the flows inside the mule tags.
Note: If these flows are not adjacent, you will need to repeat the process several times.

137

16. Switch to the Message Flow view.

17. Save all the files.

Rename the apessentials configuration file
18. Right-click apessentials.xml in the Package Explorer and select Refactor > Rename.
19. In the Rename Resource dialog box, enter a new name of getFlights.xml and click OK.

20. Double-click getFlights.xml in the Package Explorer to reopen it.

138

Examine the global elements
21. Click the Global Elements tab at the bottom of the canvas.
22. Notice that all of the global elements are still defined in getFlights.xml.

Test the application
23. Run the application; you should get an error that the prefix for sfdc:query is not bound.

Add namespaces and schema locations
24. Return to the Configuration XML view for accounts.xml.
25. Look for the sfdc prefix in the beginning of the code; you should see that there is not a sfdc
namespace definition or schema location.
26. Place the cursor after  Paste.
3. In the Name Conflict dialog box, enter a name of global.xml and click OK.
4. Open global.xml.
5. Shift-click all the flows to select them all and then right-click and select Delete.
6. Click the Global Elements tab; you should see all the existing global elements.
7. Save the file.

Delete the global elements in getFlights.xml
8. Return to getFlights.xml.

141

9. Switch the editor to the Configuration XML view.

10. Select and delete the eight global elements defined before the flows.
Note: If you delete the global elements from the Global Elements view instead, the config-ref
values are also removed from the connector endpoints and you need to re-add them.
11. Save the file.
12. Return to the Message Flow view.
13. Double-click the HTTP Listener connector of any flow; the connector configuration should still be
set to HTTP_Listener_Configuration, which is now defined in global.xml.

Test the application
14. Run the application.
15. Make a request to http://localhost:8081/sfdc; you should still get account results.

142

Walkthrough 6-3: Create and run multiple applications
In this walkthrough, you will separate your project into two projects. You will:
•

Create a new project and application called apessentials2.

•

Move the examples configuration file into the apessentials2 application.

•

Create new global connector configurations in the new project.

•

Create a new run configuration to run multiple applications simultaneously.

Create a new project and application
1. Select File > New > Mule Project.
2. Set the name to apessentials2 and click Finish.
3. Right-click the apessentials2.xml file in the Package Explorer and select Delete.
4. In the Delete dialog box, click OK.

Move the examples flow into the new project
5. Drag examples.xml from the apessentials project to the src/main/app folder of the apessentials2
project; you should get reference to an unknown global element problems.

Move activemq JAR into the new project
6. Right-click apessentials2 and select New > Folder.
7. In the New Folder dialog box, set the folder name to lib and click Finish.
8. Drag activemq-all-{version}.jar.xml from the apessentials/lib folder to the apessentials2/lib
folder.
143

9. Right-click activemq-all-{version}.1jar and select Build Path > Add to Build Path; you should see
the JAR file added to Referenced Libraries.
10. In global.xml, switch to the Global Elements view.
11. Select the Active MQ configuration element and click Delete.
12. Save the file.
13. Right-click apessentials in the Package Explorer and select Properties.
14. Select Java Build Path and click the Libraries tab.
15. Select activemq-all-{version}.jar and click Remove.

16. Click OK.

Create new global elements
17. Right-click the apessentials2 project and select New > Mule Configuration File.
18. In the New Mule Configuration File dialog box, set the name to global and click Finish.
19. In global.xml, switch to the Global Elements view.
20. Click the Create button.

144

21. Select Connector Configuration > HTTP Listener Configuration and click OK.

22. In the Global Elements dialog box, click OK.
23. Click the Create button again and select Connector Configuration > JMS > Active MQ and click
OK.
24. In the Global Elements dialog box, set the Broker URL to tcp://54.69.115.37:61616.
25. Select Specification v1.1 and click OK.

Note: You could also copy and paste these definitions from the apessentials global.xml file.
26. Save all the files.
145

Run the new application
27. Right-click apessentials2 and select Run As > Mule Application.
28. Make a request to http://localhost:8081/sfdc; you should get Resource not found – that
application is not running.

29. Make a request to http://localhost:8081?name=pliny&type=cat using your own query parameter
values; you should get HELLO WORLD.

Create a run configuration to run multiple applications
30. Return to Anypoint Studio.
31. On the main menu bar, select Run > Run Configurations.
32. Click apessentials in the left menu bar under Mule Applications; you should see that the
apessentials project is selected to launch.
33. Click apessentials2 in the left menu bar; you should see that the apessentials2 project is
selected to launch.

146

34. Click the New Launch Configuration button.

35. Set the name to apessentials and apessentials2.
36. On the General tab, select both the apessentials and apessentials2 projects.

Run multiple applications
37. Click Run.
38. Look at the console; apessentials should have deployed and apessentiasl2 failed.

39. Scroll up the console; you should see an address already in use error.

40. Navigate to the Global Elements view in global.xml in apessentials2.
41. Double-click the HTTP Listener Configuration (or select it and click the Edit button).

147

42. In the Global Elements Properties dialog box, change the port to 8082 and click OK.

43. Save the file; both applications should now be successfully deployed – apessentials was
already deployed.

Test the application
44. Make a request to http://localhost:8081/sfdc; you should see Salesforce data.
45. Make a request to http://localhost:8082?name=pliny&type=cat using your own query parameter
values; you should get HELLO WORLD.
46. Stop the Mule runtime.
47. Click the arrow next to the Run button in the Anypoint Studio toolbar and select apessentials
and apessentials2.

148

48. Look at the console; you should both applications deployed.

49. Stop the Mule runtime.

149

Walkthrough 6-4: Create and reference flows and subflows
In this walkthrough, you will work with the apessentialsFlow in examples.xml. You will:
•

Extract processors into separate subflows and flows.

•

Use the Flow Reference component to reference other flows.

•

Create and reference synchronous and asynchronous flows.

•

Explore variable persistence through flows, subflows, and across transport barriers.

Create a subflow
1. Open examples.xml in apessentials2.
2. Drag a Sub Flow scope element to the canvas.
3. Select the Set Payload and Property transformers in the apessentialsFlow and drag them into
the subflow.
4. Change the name of the subflow to subflow1.

Reference a subflow
5. Drag a Flow Reference component from the palette and drop it into the apessentialsFlow
between the HTTP Listener connector endpoint and the Variable transformer.
150

6. In the Flow Reference Properties view, set the flow name to subflow1.

7. Add a breakpoint to the subflow1 Flow Reference.

Extract processors into a subflow
8. Right-click the Variable transformer and select Extract to > Sub Flow.
9. In the Extract Flow dialog box, set the flow name to subflow2.
10. Leave the target Mule configuration set to current and click OK.
11. Drag the Session Variable transformer into subflow2.
12. In the new Flow Reference Properties view, set the flow name to subflow2.

13. Drag subflow2 below subflow1.
14. Save the file.

151

Debug the application
15. Click the Debug button and select apessentials2 to just debug apessentials2.
16. Make a request to http://localhost:8082?name=pliny&type=cat using your own query parameter
values.
17. Step through the application, watching messages move into and out of the subflows.

18. Make another request to http://localhost:8082?name=pliny&type=cat using your own query
parameter values.
19. Step through the application again, this time watching the values of the inbound properties,
variables, outbound properties, and session variables.

Create a second flow
20. Drag a Flow scope element to the canvas.
21. Change the flow name to flow2.
22. Add a Set Payload transformer to the process section of the flow.
23. Add a breakpoint to it.

24. In the Set Payload Properties view, set the value to a string, like flow2.

Reference a flow
25. Drag a Flow Reference component from the palette and drop it into the apessentialsFlow
between the subflow2 Flow Reference and the Logger.
152

26. In the Flow Reference Properties view, set the flow name to flow2.

Debug the application
27. Save the file to redeploy the application in debug mode.
28. Make a request to http://localhost:8082?name=pliny&type=cat using your own query parameter
values.
29. Step through the application, watching the flow move into and out of the second flow; at the end,
you should see the new payload value set in the second flow returned.

30. Make another request to http://localhost:8082?name=pliny&type=cat using your own query
parameter values.
31. Step through the application again, this time watching the values of the inbound properties,
variables, outbound properties, and session variables.

Create a transport barrier for the second flow
32. In global.xml for apessentials2, switch to the Global Elements view.
33. Click Create.
34. In the Choose Global Type dialog box, select Connector Configuration > HTTP Request
Configuration and click OK.

153

35. In the Global Elements dialog box, set the host to localhost, the port to 8082, and click OK.

36. In examples.xml, drag an HTTP connector into the Source section of flow2.
37. In the HTTP Properties view, set the connector configuration to the existing
HTTP_Listener_Configuration.
38. Set the path to /flow2 and the allowed methods to GET.

39. Add a second HTTP connector after the flow2 reference in apessentialsFlow.
40. Delete the flow2 reference.
41. In the HTTP Properties view, set the connector configuration to HTTP_Request_Configuration.

154

42. Set the path to /flow2 and the method to GET.

Debug the application
43. Place a breakpoint on the Set Payload transformer in flow2.
44. Save all the files to redeploy the application.
45. Make another request to http://localhost:8082?name=pliny&type=cat using your own query
parameter values.
46. Step through the application again, pressing the Resume button to move into flow2.
47. Watch the values of the inbound properties, outbound properties, flow variables, and session
variables as you move into flow2 and then back to apessentialsFlow.
Note: Ignore any TimeoutException you may get.
Note: Session variables are persisted across some but not all transport barriers. As you see
here, they are not propagated across the HTTP transport barrier.

155

Module 7: Handling Errors

In this module, you will learn:
•

About the different types of exception strategies.

•

To handle messaging exceptions in flows.

•

To create and use global exception handlers.

•

To specify a global default exception strategy.

156

Walkthrough 7-1: Handle a messaging exception
In this walkthrough, you will handle an exception thrown by the United flow when a destination with no
flights is used. You will:
•

Add a Catch Exception Strategy to a flow.

•

Catch the exception and send an error message back to the requester.

•

Reference the exception object inside an exception handler.

•

Create and catch a web service request error.

Test the application for when United returns no results
1. Return to getFlights.xml and debug the application.
2. Make a request to http://localhost:8081/united?code=LAX.
3. Step through the application and make sure you get flight results.
4. Make a request to http://localhost:8081/united?code=FOO.
5. Step through the application and when you get the error, drill-down into the exceptionThrown
object in the debugger.

157

6. Click the Resume button.

Add a catch exception strategy
7. Return to getUnitedFlightsFlow and click the arrow to expand the Error handling section.
8. Drag and drop a Catch Exception Strategy from the Error Handling section of the palette into the
Error handling section of the flow.

9. Add a Set Payload transformer to the Catch Exception Strategy.
10. In the Set Payload Properties view, set the value the following MEL expression:

NO	
  FLIGHTS	
  to	
  #[flowVars.destination].	
  ERROR:	
  #[exception]	
  
11. Add a breakpoint to the transformer.
12. Add a Logger after the transformer.

Test the application
13. Save the file and debug the application.
14. Make another request to http://localhost:8081/united?code=FOO.

158

15. Step through the application; you should see the exception thrown in getUnitedFlightsFlow and
handled by the exception handler.

16. Step to the end of the application; you should see your message in the browser window.

Make a RESTful web service request error
17. Navigate to the United REST Request endpoint in getUnitedFlightsFlow.
18. Change the path to /{destinatio}.

Test the application
19. Save the file and debug the application.
20. Make a request to http://localhost:8081/united.
21. Step to the end of the application; the exception is handled by the same exception handler.

159

Walkthrough 7-2: Handle multiple messaging exceptions
In this walkthrough, you will handle multiple types of exceptions thrown by the United flow. You will:
•

Add and configure a Choice Exception Strategy.

•

Set HTTP status codes in the exception handler.

•

Let an exception bubble up and be handled by the calling flow.

Add a choice exception strategy
1. Drag a Choice Exception Strategy from the palette and drop it above getUnitedFlightsFlow.
2. Drag the Catch Exception Strategy from getUnitedFlightsFlow and drop it in the Choice
Exception Strategy.
3. Drag a second Catch Exception Strategy from the palette and drop it in the Choice Exception
Strategy.
Note: If you are having difficulty adding it, try dropping it on the orange banner of the Catch
Exception Strategy.

160

4. Drag the Choice Exception Strategy and drop it in the Error handling section of
getUnitedFlightsFlow.
Note: If you are having difficulty adding it because the canvas is scrolling, try changing the order
of the flows on the canvas and then dragging and dropping.
5. Add a Set Payload transformer and a Logger to the new Catch Exception Strategy.
6. In the Set Payload Properties view, set the value the following MEL expression:

DATA	
  IS	
  UNAVAILABLE.	
  TRY	
  LATER.	
  ERROR:	
  #[exception]	
  
7. Add a breakpoint to the transformer.

Configure the choice exception strategy
8. Set the name of the first Catch Exception Strategy to DataWeave exception - No flights.
9. Set the name of the second Catch Exception Strategy to Catch all others - Data unavailable.

161

10. In the Properties view for the first Catch Exception Strategy, add an expression so it executes
when a com.mulesoft.weave.* exception is thrown; use the causeMatches() method.

#[exception.causeMatches('com.mulesoft.weave.*')]	
  

	
  
11. In the Properties view for the second Catch Exception Strategy, do not set an execute when
expression.

Test the application
12. Save the file and debug the application.
13. Make another request to http://localhost:8081/united.
14. Step through the application; the exception should be handled by the second catch block.

15. Step to the end of the application; you should see the second error message.

162

Fix the RESTful web service request error
16. Navigate to the United REST Request endpoint in getUnitedFlightsFlow.
17. Change the path back to /{destination}.

Test the application
18. Save the file and debug the application.
19. Make a request to http://localhost:8081/united?code=FOO.
20. Step through the application; the exception should be handled by the first Catch Exception
Strategy.

21. Step to the end of the application; you should see the first error message.

163

22. If you are using Postman, locate the http status code value.

Set http status codes
23. Add a Property transformer before the Logger in both Catch Exception Strategies.

24. In the first Property transformer Properties view, set the property http.status to 400.

164

25. In the second Property transformer Properties view, set the property http.status to 500.

Test the application
26. Save the file and debug the application.
27. Make a request to http://localhost:8081/united?code=FOO.
28. Step through the application; you should see the outbound http.status property set to 400.

29. Step to the end of the application; if you are using Postman, you should see the new http status
code value.

Call the United flow from another flow
30. Locate getFlightsFlow.
31. Add a Flow Reference before the Logger.

165

32. Set the flow name for the Flow Reference to getUnitedFlightsFlow.

Move a catch exception strategy to the calling flow
33. Expand the Error handling section of getFlightsFlow.
34. Move the Choice Exception Strategy from getUnitedFlightsFlow to getFlightsFlow.

Test the application
35. Save the file and debug the application.
36. Make sure there are breakpoints in the flow and the two Catch Exception Strategies.
37. Make a request to http://localhost:8081/flights and submit the form.
166

38. Step through the application; you should see the United flow called and the exception caught by
the calling flow.
Note: You will have to click the Resume button to move into the exception strategy after the
exception is thrown by the United flow.

167

Walkthrough 7-3: Create and use global exception handlers
In this walkthrough, you will create a global exception handler in the MUA application. You will:
•

Create a global exception handler.

•

Reference and use the global exception handler in flows.

Test the application for when Delta returns no results
1. Return to getFlights.xml and debug the application.
2. Make a request to http://localhost:8081/delta?code=LAX.
3. Step through the application and make sure you get flight results.
4. Make a request to http://localhost:8081/delta?code=FOO.
5. Step through the application and when you get the error, drill-down into the exceptionThrown
object in the debugger.

6. Click the Resume button.

Create a global exception handler
7. In getFlights.xml, switch to the Configuration XML view.

168

8. Locate the Choice Exception Strategy and select it and cut it.

9. Open global.xml and go to the Configuration XML view.
10. Return to getFlights.xml and cut the getFlightsChoice_Exception_Strategy from the
getFlightsFlow.
11. Paste the Choice Exception Strategy after the global configuration elements inside the start and
end mule tags.
12. Switch to the Message Flow view; you should see the Choice Exception Strategy.

Use the global exception handler
13. Return to getFlights.xml and switch to the Message Flow view.
14. Locate the getUnitedFlightsFlow and expand its Error handling section.

169

15. Drag a Reference Exception Strategy from the palette and drop it in the Error handling section.

16. In the Properties view, set the global exception strategy to
getFlightsChoice_Exception_Strategy.

17. Drag a Reference Exception Strategy to the error handling section of getDeltaFlightsFlow.
18. In the Properties view, set the global exception strategy to
getFlightsChoice_Exception_Strategy.
Note: You could add a Reference Exception Strategy to the rest of the flows, but instead, you
will create a global default exception strategy in the next walkthrough.

Test the application
19. Save all the files and run the application.
20. Make a request to http://localhost:8081/united?code=FOO; you should see the data unavailable
error message displayed.

170

21. Make a request to http://localhost:8081/delta?code=FOO; you should see the data unavailable
error message displayed.

171

Walkthrough 7-4: Specify a global default exception strategy
In this walkthrough, you will change the default exception handling for the application. You will:
•

Create a global configuration element in the global.xml file.

•

Specify a default exception strategy in the global configuration element.

•

Remove the existing exception handling strategies.

•

Use the default exception handling strategy.

Specify a global default exception strategy
1. Return to global.xml.
2. Switch to the Global Elements view.
3. Click the Create button.
4. In the Choose Global Type dialog box, select Global Configurations > Configuration and click
OK.

172

5. In the Global Element Properties dialog box, set the default exception strategy to
globalChoice_Exception_Strategy and click OK.

6. Locate your new global configuration element.

Remove the existing exception strategy references
7. Return to getFlights.xml.
8. Delete the Reference Exception Strategy in getUnitedFlightsFlow.
9. Delete the Reference Exception Strategy in getDeltaFlightsFlow.

173

Test the application
10. Save all the files and run the application.
11. Make a request to http://localhost:8081/united?code=FOO; you should still see the no flights
error message displayed.

12. Make a request to http://localhost:8081/delta?code=FOO; you should still see the no flights error
message displayed.

13. Stop the Mule runtime.

174

Module 8: Controlling Message
Flow

In this module, you will learn:
•

About flow control and filter elements.

•

To multicast a message.

•

To route message based on conditions.

•

To filter messages.

•

About synchronous and asynchronous flows.

•

To create an asynchronous flow.

175

Walkthrough 8-1: Multicast a message
In this walkthrough, you will create one flow that calls each of the three airline services and combines
and returns the results back to the web form. You will:
•

Use a Scatter-Gather router to concurrently call all three flight services.

•

Use a Combine Collections transformer to combine a collection of three ArrayLists of objects
into one collection.

•

Use DataWeave to sort the flights and return them as JSON to the form.

Add a router to call all three airline services
1. Return to getFlights.xml.
2. Add a Scatter-Gather flow control element before the Flow Reference in getFlightsFlow.
3. Drag the Flow Reference component into the Scatter-Gather router.

4. Add a second Flow Reference component to the Scatter-Gather router.
5. In the Properties view for the Flow Reference, set the flow name to getDeltaFlightsFlow.
6. Add a third Flow Reference component to the Scatter-Gather router.
176

7. In the Properties view for the Flow Reference, set the flow name to getAmericanFlightsFlow.
8. Add a breakpoint to the Set payload and destination flowVar component.
9. Add a breakpoint to the Logger.
10. Save the file.

Test the application
11. Debug the application.
12. Make a request to http://localhost:8081/flights and submit the form.
13. Step through the application to the Logger; you should step through each of the airline flows.
14. Look the Mule Debugger view and see what the data type of the payload is after the router.

Note: If you step through to the end of the application, ignore any errors you get.
15. Click the Resume button.

177

Flatten the results
16. Add a Combine Collections transformer before the Logger.

Test the application
17. Save the file to redeploy the application.
18. Make a request to http://localhost:8081/flights and submit the form.
19. Step through the application to the Logger after the router; you should see the payload is now
one ArrayList of HashMaps.

178

20. Step through to the end of the application; you should see a jumble of data returned.

Review HTML form code to see what data format it expects
21. Open FlightFinder.html in src/main/resources and locate in what format it expects the data to be
sent back.

Return the data as JSON and sort by price
22. In getFlights.xml, add a Transform Message component after the Combine Collections
transformer.
23. Change its name to Java to JSON

24. In the Java to JSON Properties view, change the output type to application/json.
25. Write a DataWeave expression to transform the payload and order by price.

179

Test the application
26. Save the file and run the application.
27. Make a request to http://localhost:8081/flights and submit the form; you should see SFO flights
for all three airlines returned and the flights should be sorted by price.

28. Submit the form for different destinations; flights for SFO are returned every time.

Use the destination in the airline flows
29. Locate the Set Destination transformer in the getAmericanFlightsFlow.
Note: There are two options at this point: 1) to remove the HTTP endpoints and Set Destination
transformers from each of the airline flows or 2) to use a more complicated expression to check
and see if a destination flow variable already exists so that the individual airline flows can still be
called and tested individually.
30. Modify the value so it only uses the expression to set the destination flowVars variable if it does
not already exist.

#[(flowVars.destination	
  ==empty	
  &&	
  
message.inboundProperties.'http.query.params'.code	
  ==	
  empty)	
  ?	
  'SFO'	
  :	
  
(flowVars.destination	
  !=	
  empty	
  ?	
  flowVars.destination	
  :	
  
message.inboundProperties.'http.query.params'.code)]	
  
Note: This expression is located in the course snippets.txt file and can be copied from there.
180

31. Use the same expression in the Set Destination in the getDeltaFlightsFlow and
getUnitedFlightsFlow.

Test the application
32. Save the file to redeploy the application.
33. Make a request to http://localhost:8081/flights and submit the form; you should still see SFO
flights.
34. Submit the form for a different destination including LAX, CLE, or PDX; you should see the
correct flights returned.

35. Submit the form for a destination of PDF or FOO; you should get an error in the console but no
return error message to the form.
36. Submit the form for SFO, LAX, CLE, or PDX and a different airline; you should still see flights for
all three airlines returned.

181

Walkthrough 8-2: Route messages based on conditions
In this walkthrough, you will create a flow that routes messages based on conditions. You will:
•

Use a Choice router to get flight results for all three airlines or only a specific airline.

•

Set the router paths based on the airline value sent from the flight form.

Look at selected airline values in HTML form
1. In Anypoint Studio, return to FlightFinder.html.
2. Locate the select box that sets the airline and see what values are set and returned.

Move the Scatter-Gather to a separate flow
3. Return to getFlights.xml.
4. Shift+click to select the Scatter-Gather router and the Combine Collections transformer.
5. Right-click and select Extract to > Flow.
6. In the Extract Flow dialog box, set the flow name to getAllAirlinesFlightsFlow.

182

7. Leave the target Mule configuration set to current and click OK.

8. In getFlightsFlow, double-click the new Flow Reference.
9. Change its display name to getAllAirlinesFlightsFlow.
10. Move getAllAirlinesFlightsFlow beneath getFlightsFlow.
11. Add a breakpoint to the Combine Collections transformer.

Add a Choice router
12. In getFlightsFlow, add a Choice flow control element between the Set payload and destination
flowVar component and the getAllAirlinesFlightsFlow flow reference.
13. Drag the getAllAirlinesFlightsFlow flow reference into the router.
14. Add a new Logger component to the default branch.

15. Add three additional Flow Reference components to the Choice router to create a total of five
branches.
16. In the Properties view for the first new flow reference, set the flow name to
getUnitedFlightsFlow.
17. In the Properties view for the second flow reference, set the flow name to getDeltaFlightsFlow.
183

18. In the Properties view for the third flow reference, set the flow name to getAmericanFlightsFlow.

Configure the Choice router
19. In the Properties view for the Choice router, double-click the getAllAirlinesFlightsFlow route.
20. In the Route Properties dialog box, set the expression to #[payload.airline== "all"] and click OK.

21. Set a similar expression for the United route, routing to it when payload.airline is equal to united.
22. Set a similar expression for the Delta route, routing to it when payload.airline is equal to delta.

184

23. Set a similar expression for the American route, routing to it when payload.airline is equal to
american.

Debug the application
24. Save the file and debug the application.
25. Make a request to http://localhost:8081/flights.
26. On the form page, leave SFO and All Airlines selected and click Find Flights.
27. Return to the Mule Debugger view and step through the application; you should see the Choice
router pass the message to the getAllAirlinesFlightsFlow branch.

28. Click the Resume button until flight data for all airlines is returned back to the form page.
29. On the form page, select SFO and United and click Find Flights.
30. Return to the Mule Debugger view and step through the application; you should see the Choice
router pass the message to the United branch.
185

31. Click the Resume button until flight data is returned back to the form page; you should see only
United flights.

Test the application
32. Stop the debugger and run the application.
33. Make a request to http://localhost:8081/flights.
34. Test the Delta and American choices with SFO, LAX, or CLE; you should see the appropriate
flights returned.
35. Test the PDF location with United; you should see one flight.

186

36. Test the PDF location with Delta; you should get an error in the console.
37. Test the PDF location with American; you should get no error, but no results.

38. Test the PDF location with All Airlines; you should get no results and an error in the console.

Debug the application
39. Debug the application.
40. Make a request to http://localhost:8081/flights and submit the form with PDF and All Airlines.
41. Step through the application to the Combine Collections transformer; you should see different
types of objects returned.

42. Step to the Java to JSON component; you should see the payload still contains the error
message in addition to the valid flight results to PDF.
43. Step to the end of the application; you should not get the United results to PDF.
Note: You could write a custom aggregation strategy for the Scatter-Gather component with
Java to handle this situation, but instead you will use the simpler approach of filtering out the
exception messages.

187

Walkthrough 8-3: Filter messages
In this walkthrough, you will continue to work with the airline flight results. You will:
•

Filter the results in the multicast to ensure they are ArrayLists and not exception strings.

•

Use the Payload and Expression filters.

•

Create and use a global filter.

Add a filter
1. Return to getFlights.xml.
2. Drag out a Payload Flow Control element from the palette and drop it after the
getDeltaFlightsFlow reference in the Scatter-Gather.

3. In the Payload Properties view, set the expected type to java.util.ArrayList.

188

Test the application
4. Save the file and debug the application.
5. Make a request to http://localhost:8081/flights and submit the form with PDF and All Airlines.
6. Step through the Java to JSON component; this time you should see the payload only contains
the ArrayList and not the error string.
7. Step to the end of the application; you should see the United results to PDF returned to the
form.

Create a global filter
8. Delete the Payload filter.
9. Return to global.xml.
10. Switch to the Global Elements view and click Create.
11. In the Choose Global Type dialog box, select Filters > Payload and click OK.

189

12. In the Global Elements dialog box, set the name to Filter_Not_ArrayList.
13. Set the expected type to java.util.ArrayList and click OK.

14. See your new global filter in the list.

Use the global filter
15. Return to getFlights.xml.
16. Drag a Filter Reference from the palette and drop it after getDeltaFlightsFlow in the ScatterGather.

190

17. In the Filter Reference Properties view, set the display name to Filter not an ArrayList and set
the global reference to Filter_Not_ArrayList.

18. Add a Filter Reference after getAmericanFlightsFlow.
19. In the Filter Reference Properties view, set the display name to Filter not an ArrayList and set
the global reference to Filter_Not_ArrayList.
20. Copy and paste the Filter Reference in the Scatter-Gather.
21. Drag it after getUnitedFlightsFlow and change its name to Filter not an ArrayList.

Test the application
22. Save all the files and run the application.
23. Make a request to http://localhost:8081/flights and submit the form with PDF and All Airlines;
you should still see the United results.

191

24. Submit the form for FOO and All Airlines; you should get no results and no message.

Look at the HTML form and find the display if no flights are returned
25. In Anypoint Studio, return to or open FlightFinder.html.
26. Locate the code that sets the text if there is no flights are returned.

Add an Expression filter to filter no results
27. In the getFlightsFlow, add an Expression filter after the Choice router.
28. In the Expression Properties view, set the display name to Filter No Results.
29. Set the expression to see if the payload is equal to an empty Array.

#[payload!=[]]	
  

Test the application
30. Save the file to redeploy the application.
192

31. Submit the form for FOO and All Airlines; you should see the message there are no available
flights in the browser window.

44. Test the PDF location with American; you should get the no available flights message.
Note: If you test the PDF location with United or Delta, you should get no results and an error in
the console: Execution of the expression "exception.causeMatches('com.mulesoft.weave.*')"
failed. This is a bug in 3.7.1. As a workaround, you can modify the global Catch Exception
Strategy for DataWeave expressions to
#[message.?exception.causeMatches('com.mulesoft.weave.*'), but you will also need to add
some more logic to return the desired results.

193

Walkthrough 8-4: Pass messages to an asynchronous flow
In this walkthrough, you will work in the apessentials2 project and create and pass messages to an
asynchronous flow. You will:
•

Use the Async scope element to create an asynchronous flow.

•

Use the Mule Debugger to watch messages flow through both flows.

Create an asynchronous flow
1. Return to examples.xml in apessentials2.
2. Drag an Async scope element from the palette and drop it into the apessentialsFlow between
the HTTP Request endpoint and the Logger.
3. Delete the HTTP Request endpoint in apessentialsFlow.
4. Drag a Flow Reference into the Async scope.
5. In the Flow Reference Properties view, set the flow name to flow2.
6. Add three more Logger components after the Async scope.

7. Delete the HTTP Listener endpoint in flow2.
8. Add a Logger component after the Set Payload in flow2.
9. Make sure there is a breakpoint on the Set Payload in flow2.

194

Debug the application
10. Save the file and debug the application.
11. Make another request to http://localhost:8082?name=pliny&type=cat using your own query
parameter values.
12. Step through the application again; you should see a copy of the message passed to the
asynchronous flow2.
13. Watch the values of the payload change in both flows.

195

Module 9: Processing Records

In this module, you will learn:
•

Process items in a collection individually.

•

Use DataWeave with CSV files.

•

Use the Batch Job element (EE) to process individual records.

•

Synchronize data from a CSV file to a SaaS application.

•

Synchronize data from a legacy database to a SaaS application.

196

Walkthrough 9-1: Process items in a collection individually
In this walkthrough, you will split a collection and process each item in it individually. You will:
•

Add metatdata to a File endpoint.

•

Read a CSV file and use DataWeave to convert it to a collection of objects.

•

Use the For Each scope element to process each item in a collection individually.

Modify the File endpoint to not rename the files
1. Open accounts.xml.
2. In the Package Explorer, expand the src/main/resources/input folder.
3. Right-click accounts.csv.backup and select Refactor > Rename.
4. In the Rename Resource dialog box, set the new name to accounts.csv and click OK.
5. In getCSVAccountsFlow, delete the File-to-String transformer.
6. In the File Properties view, delete the move to pattern.
Note: This will make it easier to test the application because you won’t have to keep renaming
the file as you move it back to the input directory.

Add File endpoint metadata
7. In the File Properties view, click Metadata in the left-side navigation.
8. Click the Add metadata button.
9. In the drop-down menu that appears, make sure Output: Payload is selected.

10. Click the Edit button next to the drop-down menu.
11. In the Define Type dialog box, select Create new type.
197

12. Change the type to CSV.
13. Set the Type Id to Accounts_CSV.
14. Make sure CSV includes header row is checked.
15. Click the Load from example button (the folder icon).

16. In the Load CSV fields from file dialog box, click the Browse button next to Example.
17. In the Select CSV example dialog box, browse to the project’s src/main/resources/input folder,
select accounts.csv, and click Open.
18. In the Load CSV fields from file dialog box, click OK.

198

19. In the Define Type dialog box, click Finish.

Use DataWeave to convert a CSV file to a collection of objects
20. Add a Transform Message component between the File and the Logger.
21. Change the name of the component to CSV to Maps.

22. In the Input section of the Transform Message Properties view, make sure the Payload is
specified as a List with appropriate fields.
23. Look at the Transform section, the output should be set to application/java.
24. Look at the Output section, the Payload should be set to a Map.

199

25. Write a DataWeave expression to transform the payload without making any changes to its
structure or values.
26. Look at the preview.

27. Run the application.
28. Return to the console in Anypoint Studio; you should see the values for all the accounts in the
CSV file displayed.

Add a For Each scope element
29. Drag a For Each scope element form the palette and drop it after the Transform Message
component.
30. Add a Logger to the For Each scope.

200

Process each element
31. In the Logger Properties view, set the message to #[payload].

Debug the application
32. Add a breakpoint to the Transform Message component.
33. Save the file and debug the application.
34. Drag accounts.csv from the src/main/resources/output folder to the src/main/resources/input
folder; application execution should stop at the Transform Message component.
35. In the Mule Debugger view, watch the payload value.
36. Step to the For Each scope; the payload should be an ArrayList of LInkedHashMaps.
37. Step through the For Each; the payload should be a LinkedHashMap.

38. Watch the console as you step through; you should see each record displayed.

39. Step through to the Logger after the For Each; the payload should be an ArrayList again.

201

Walkthrough 9-2: Create a batch job for records in a file
In this walkthrough, you will create a batch job to process records in a CSV file. You will:
•

Create a new flow containing a batch job.

•

Explore flow and record variable persistence across batch steps and phases.

•

In the input phase, check for CSV files every second and convert them to a collection of objects.

•

In the process records phase, create two batch steps for setting and tracking variables.

•

In the on complete phase, display the number of records processed and failed.

Create a batch job
1. Return to accounts.xml.
2. Drag a Batch scope element from the palette and drop it above the getCSVAccountsFlow.
3. Change the batch job name to accountsCSVBatch.

Add elements to the input phase
4. Select the File and Transform Message elements in getCSVAccountsFlow and select Edit >
Copy or press Cmd+C/Ctrl+C.
5. Click in the accountsCSVBatch input phase and select Edit > Paste or press Cmd+V/Ctrl+V.

202

6. Rename the elements to remove Copy_of_ from their names.
7. Add a Variable transformer after the transformer in the input phase.
8. In the Variable Properties view, change the display name to Set size and select Set Variable.

9. Set the name to size and the value to #[payload.size()].

Add processors to a batch step in the process records phase
10. Add a Variable transformer to the batch step in the process records phase.
11. In the Properties view, select Set Variable and set the name to fname and the value to
#[payload.Name].
12. Add a Record Variable transformer to the batch step.
13. In the Properties view, select Set Record Variable and set the name to rname and the value to
#[payload.Name].
14. Add a Logger component to the batch step.

15. In the Logger Properties view, set the message to display the record variable.

#['\n\nRecordVar:	
  '	
  +	
  recordVars.rname]	
  
Note: If you want to add line breaks, add one or more ‘\n’ to your MEL expression – meaning it
must be inside the #[].
Note: Anypoint Studio 5.2.0 does not display record variables in the Mule Debugger, so you are
displaying the value in the console. If you are using a later release that does display record
variables, you can skip the steps to display the record variable.

203

Create a second batch step
16. Drag a Batch Step scope element from the palette and drop it in the process records phase
after the first batch step.
17. Add a Logger to the second batch step.

18. In the Logger Properties view, set the message to display the record variable.

#['\n\nRecordVar:	
  '	
  +	
  recordVars.rname]	
  

Add processors to the on complete phase
19. Add a Logger component to the on complete phase.
20. In the Logger Properties view, set the message to display the number of processed records and
failed records.

#['\n\nProcessed:	
  '	
  +	
  payload.processedRecords	
  +	
  '	
  Failed:	
  '	
  +	
  
payload.failedRecords]	
  

Stop the getCSVAccountsFlow from running
21. Double-click getCSVAccountsFlow.
22. In the Properties view, set the initial state to stopped.

Debug the application
23. Add a breakpoint to the CSV to Maps component in accountCSVBatch.
24. Save the file to redeploy the application in debug mode.
25. After the application starts, drag the accounts.csv file from the output folder to the input folder.
26. In the Mule Debugger view, watch the payload value.
204

27. Step into the process records phase.
28. Click the Variables tab; you should see the size flow variable.
29. Step to the Logger in the first batch step; you should see the fname flow variable.

30. Click the Record tab; you should see the rname flow variable.
Note: Anypoint Studio 5.2.0 does not display record variables in the Mule Debugger.
31. Click the Variables tab.
32. Step through the rest of the records in the first batch step and watch the payload and the fname
variable.
33. Look at the console; you should see the values for the rname record variable displayed.

34. Step into and through the second batch step; watch the payload, the variables, the record
variables, and the console.
35. Look at the console; you should see the values for the rname record variable displayed again
for each record.

205

36. Step into the on complete phase; you should see the payload is an ImmutableBatchJobResult.

37. Step to the end of the application; you should see the number of process records phase and
failed records in the console.

206

Walkthrough 9-3: Create a batch job for records in a database
In this walkthrough, you will create a batch job that retrieves records from a legacy database. You will:
•

Go to a form and add multiple accounts for a specific postal code to the database.

•

Create a new flow containing a batch job that polls a MySQL database every 30 seconds for
records with a specific postal code.

•

Use the Poll scope.

Get familiar with the data in the database
1. In a browser, go to the account list URL for the MySQL database listed in the course
snippets.txt file.
2. Look at the existing data and the name of the columns, which match the names of the database
fields.

3. Click the Create More Accounts button.
4. Add one or more new records with a specific postal code; you will retrieve these records in this
walkthrough and insert them into your Salesforce accounts in the next walkthrough.

207

Create a batch job that polls a database
1. Return to accounts.xml.
2. Drag a Batch scope element onto the canvas from the palette to create a new flow.
3. Add a Poll scope element to the input phase.
4. In the Properties view, select the fixed frequency scheduler.
5. Set the frequency to 30 and the time unit to seconds.
6. Add a Database connector to the poll.

7. Set the connector configuration to the existing Training_MySQL_Configuration global element.
8. Set the operation to Select.
9. Add a query to select the data for your postal code.

SELECT	
  *	
  
FROM	
  accounts	
  
WHERE	
  postal	
  =	
  '94108'	
  

Log each record to the console in the process records phase
10. Add a Logger component to the Process Records phase.
11. Display the record – the message payload – and other text or information you wish.

#['\n\nRECORD:	
  '	
  +	
  payload]	
  

Log processed records in on complete phase
12. Add a Logger component to the on complete phase.
13. Set the Logger message to display the number of processed records and failed records.

#['\n\nProcessed:	
  '	
  +	
  payload.processedRecords	
  +	
  '	
  Failed:	
  '	
  +	
  
payload.failedRecords]	
  

208

Test the application
14. Run the application and watch the console; you should see records displayed every 30
seconds.

Note: Right now, all records with matching postal code are retrieved – over and over again. In
the next walkthrough, you will modify this so only new records with the matching postal code are
retrieved.

209

Walkthrough 9-4: Restrict processing using a poll watermark
In this walkthrough, you will modify the poll so it only retrieves new database records with a specific
postal code. You will:
•

Modify the Poll to use a watermark to keep track of the last record returned from the database.

•

Modify the database query to use the watermark.

•

Clear application data.

Use a watermark to keep track of the last record
1. Return to accounts.xml.
2. In the Poll Properties view, select Enable watermark.
3. Set the watermark to store the max accountID returned by setting the following values.
•

Variable name: lastAccountID

•

Default expression: 0

•

Selector: MAX

•

Selector Expression: #[payload.accountID]

210

Debug and examine the watermark value
4. Place a breakpoint on the Logger in the on complete phase.
5. Debug the application.
6. Find your watermark variable in the Variables section of the Mule Debugger view; initially, you
should see a default value of zero.

7. Run the application though until the next polling event – the next time it retrieves records from
the accounts table; the watermark variable should now be equal to the max accountID for
training accounts records with the postal code you are using.

8. Resume the application multiple times; the same records should still be selected over and over
again.

211

Modify the database query to use the watermark
9. In the Database Properties view, modify the query so it only returns records for your postal code
and with accountID values greater than the watermark lastAccountID value.

Test the application
10. Run the application and look at the console; you should see that no records are retrieved at all
this time.

Note: By default, the watermark is stored in a persistent object store so its value is retained
between different executions of the application.

Clear application data
11. Select Run > Run Configurations.
12. Make sure your apessentials project is selected and then on the General tab, change Clear
Application Data from Never to Prompt.
13. Run or debug your application again; you should be prompted to clear the application data.
14. Click Yes.

15. Look at the console; you should see the latest matching records retrieved from the legacy
database again – but this time, only once.
212

16. Watch the console and see that all subsequent polling events retrieve no records.

213

Walkthrough 9-5: Restrict processing using a message enricher
and a batch step filter
In this walkthrough, you will add logic to check and see if an account already exists in Salesforce before
adding it. You will:
•

Add a first batch step with a Message Enricher scope element that checks if a record already
exists in Salesforce (an account with the same Name) and stores the result in a record variable
and retains the original payload.

•

Modify the second batch step to use a filter that only allows new records (records that don’t
already exist) to be processed.

•

(Optional) Add the record(s) to Salesforce.

Add a Salesforce account manually
1. In a browser, go to http://salesforce.com and log in with your Salesforce Developer account.
2. Click the Accounts link in the main menu bar.
3. In the view drop-down, select All Accounts with Postal Code and click the Go button.
4. Click the New Account button.
5. Enter an account name (one that matches one of the accounts you added with your postal code
to the MySQL database) and click Save.

214

Check to see if a record already exists in Salesforce
6. Return to Anypoint Studio.
7. Return to accountsBatch in accounts.xml.
8. Drag out a new Batch Step scope element and drop it at the beginning of the process records
phase.
9. Add a Salesforce connector to the new batch step.

10. Configure the Salesforce connector endpoint to use the existing Salesforce connector
configuration.
11. Set the operation to Query.
12. Click the Query Builder button.
13. Set the type to Account(Account).
14. Select a field of Name; it does not matter what you select, you just want to see if any records
are returned.
15. Click the Add Filter button.
16. Create a filter to check if the Name field in the record being processed already exists in the
database.

Name	
  =	
  #[payload.Name]	
  
Note: Right now, you can use payload.name or payload.Name because the payload is a
caseSensitiveHashMap. Later this walkthrough, however, you will transform the Map to an
Account object with a Name property and will have to refer to this as payload.Name.
17. Click OK.

215

Add a Message Enricher
18. Add a Message Enricher scope element to the first batch step.
19. Move the Salesforce connector endpoint so it is inside the message enricher.
20. In the Message Enricher Properties view, set the display name to Check Record Exists.

21. Set the source to an expression that checks to see if any records were returned, i.e. if there is a
payload.

#[payload.size()	
  >	
  0]	
  
22. Set the target to assign the result of the source expression to a record variable called exists.

#[recordVars.exists]	
  

Set a filter for the insertion step
23. Double-click the second batch step that will/would insert the record into Salesforce.
24. In the Batch Step Properties view, set the Accept Expression so that only records that have a
record variable exists set to false are processed.

#[!recordVars.exists]	
  

216

Test the application
25. Add a breakpoint to the Message Enricher.
26. Add a Logger after the Message Enricher in the first batch step and add a breakpoint to it.

27. In the Logger Properties view, set the value to display the exists record variable.

#['\n\nRecordVar:	
  '	
  +	
  recordVars.exists]	
  
28. Add a breakpoint to the Logger in the second batch step.
29. Debug the application and clear the application data.
30. Watch the console in Anypoint Studio; you should see the exists record variable set to false for
all the records except the one you already added to Salesforce.

Commit new account records to Salesforce (optional)
31. Add a Salesforce connector to the second batch step in the processing phase.
32. Configure the Salesforce connector endpoint to use the existing Salesforce connector
configuration.
33. Set the operation to Create.
34. Set the sObject Type to Account (Account).

217

35. Leave the sObject Field Mappings to From Message #[payload].

36. Look at the DataSense Explorer and see a problem indicated for the payload; it is a Map but the
outbound connector is expecting a List of Account objects.

37. Drag out a Batch Commit scope and drop it in the second batch step.
38. Add the Salesforce endpoint to it.

39. In the Batch Commit Properties view, set the commit size to 100.

Transform the record data
40. Copy the Salesforce endpoint in the second batch step and paste it after the poll in the input
phase.

218

Note: You are temporarily adding this Salesforce endpoint after the Database endpoint so
DataSense will work to create the mappings. You could also add the DataWeave transformation
to the process records phase, but this would add additional overhead.
41. Add a Transform Message component between the Poll scope and the Salesforce endpoint.
42. Change the name of Transform Message component to Maps to Accounts.

43. Look at the Transform Message Properties view; DataSense should work with DataWeave to
automatically create a scaffold for a transformation to convert the database List of Map objects
to a Salesforce List of Account objects.

219

44. Modify the DataWeave expression to only keep the Name, BillingStreet, BillingCity, BillingState,
BillingPostalCode, and BillingCountry fields.

45. Change the expression to use the use the map operator to map the payload.
46. Replace the placeholder values with references to the corresponding property in the input.

47. Delete the Salesforce endpoint in the input phase.

48. Save the file.

Test the application
49. Locate the Salesforce endpoint in getSFDCAccountsFlow.

220

50. Modify the query so it selects accounts with the postal code you have been using this module.

51. Run the application and clear the application data.
52. Check the console and make sure you see your new records processed.
53. Make a request to http://localhost:8081/sfdc; you should see your new records from the legacy
MySQL database now in the Salesforce database.

54. Run the application again; no records should be processed.
Note: Remember you can also go the Salesforce web application and view, edit, and delete
Account records.

221

Module 10: Building RESTful
Interfaces with RAML and APIkit

In this module, you will learn:
•

To define an API with RAML.

•

To create RAML files with Anypoint Designer.

•

To implement a RAML file as a RESTful web service with Anypoint Studio and APIkit.

222

Walkthrough 10-1: Use API Designer to define an API with RAML
In this walkthrough, you will create an API definition for MUA with RAML. You will:
•

Add a new API to the Anypoint Platform.

•

Use the API Designer to create a RAML file.

•

Use a nested resource for the destination and a query parameter for the airline.

Add a new API
1. In a browser, go to http://anypoint.mulesoft.com and log in.
15. Click the APIs link in the main menu bar.
16. Click the Add new API button.

223

17. In the Add API dialog box, enter the following and then click Add.
•

API name: MUA Flights API

•

Version name: 1.0

•

Description: Returns flights for a given airport code destination

18. Take a look at the different sections and links for the API in the API administration.

224

19. Click the Define API in API designer link; the API Designer should open.

Note: To change the background color from black to white, press Ctrl-Shift-T.

Add RAML root metatdata
20. Place the cursor on a new line of code at the end of the file.
21. Click the baseUri element in the API Designer shelf to add it to the RAML file.
Note: Leave the default value #baseUri: http://server/api/{version} for now during development.

Add a RAML resource
22. Go to a new line of code and add a resource called flights.

/flights:	
  

Add a nested RAML resource
23. Indent by pressing the Enter key and then the Tab key.
24. Add a nested resource to return flights for a particular destination.

Add a RAML method
25. Go to a new line of code, press the Tab key, and then press the G key and then the Enter key to
add a get method.
26. Indent by pressing the Enter key and then the Tab key.
225

27. Scroll down in the API Designer shelf and locate and click responses.

Note: If you don’t see the API Designer shelf, it is either minimized or there is an error in your
code. To check if it is minimized, scroll down to the bottom of the browser window and look for
its icon. If you see it, click it to expand it. If you don’t see its icon and you also don’t see the API
Designer console, you probably have an error in your code, like a missing RAML definition.

28. Indent and type 200:.

responses:	
  
	
  	
  	
  	
  	
  	
  200:	
  
29. Indent and type b and then press Enter to add a body parameter (or add it from the shelf).
30. Indent and type a and then press Enter to add application/json (or add it from the shelf).

Note: This is the minimal RAML file needed for Anypoint Studio and APIkit to generate the
RESTful interface.

226

Add a query parameter
31. Go to a new line of code after get:.
32. Press the q key and then the Enter key to add queryParameters.
33. Indent and add a query parameter called airline.
34. Indent and add a default property and set it to all.
35. Return and add an enum property and set it to an array with values all, united, delta, and
american.

36. Click the Save button to save the RAML file.

227

Walkthrough 10-2: Use API Designer to simulate an API
In this walkthrough, you will add example responses to the API definition and test it by running a live
simulation. You will:
•

Use the API console in API Designer.

•

Use RAML to specify example responses for your API.

•

Use the API Designer mocking service to run a live simulation of your API.

Use the API Designer console
1. Return to your MUA Flights API in API Designer.
2. Look at the API console.
Note: If you do not see the console, click the arrow located in the middle of the right edge of the
browser window.

228

37. Click the GET button for the /flights/{destination} resource; you should see the request
information.

38. Scroll down to the Responses section and see the specification for a 200 status code.
39. Scroll back up and click the Try it button.
40. Enter a destination of SFO and click the GET button.

229

41. Look at the response; you should get a 500 status code because the baseUri is not found.

Use the mocking service
42. Locate the Mocking Service slider in the menu bar above the console.
43. Slide it to on.

44. Look at the new baseUri in the editor.

45. In the API console, click the Try it button for the /flights/{destination} resource again and then
enter a destination and click GET; you should now get a 200 status code.

230

46. Scroll down and look at the body; you should get a general RAML message placeholder.

47. Close the /flights/{destination} window.

Add examples
37. Return to the course snippets.txt file and copy the Example JSON.

[{"airlineName":"United","price":400,"departureDate":"2015/03/20",	
  
"planeType":"Boeing	
  737","origination":"MUA","flightCode":"ER38sd",	
  
"availableSeats":0,"destination":"SFO"},{"airlineName":"United",	
  
"price":945,"departureDate":"2015/09/11","planeType":"Boeing	
  757",	
  
"origination":"MUA","flightCode":"ER39rk","availableSeats":54,	
  
"destination":"SFO"},{"airlineName":"United","price":954,	
  
"departureDate":"2015/02/12","planeType":"Boeing	
  777",	
  
"origination":"MUA","flightCode":"ER39rj","availableSeats":23,	
  
"destination":"SFO"}]	
  
48. Return to the API Designer editor and indent from the application/json element and add an
example element.
49. Add a space and then a | after the example element.

231

50. Indent and paste the JSON array you just copied.

View the example data in the simulation
51. Return to the API console.
52. Click the GET button for the /flights/{destination} resource again.
53. Click Try it, enter a destination, and click GET.
54. Look at the response body; you should now get your example data.

Save and export the RAML file
55. Slide the Mocking Service slider to off.
56. Save the file.
57. Right-click api.raml in the left pane and select Rename.

232

58. Change the name to mua.raml and click OK.
59. Click the Export files button to download the RAML file.

60. Locate the MUA_Flights_API-v1.0.zip file that is downloaded.
61. Expand the ZIP and locate the mua.raml file it contains.

233

Walkthrough 10-3: Use Anypoint Studio to create a RESTful API
interface from a RAML file
In this walkthrough, you will generate a RESTful interface from the RAML file. You will:
•

Add a RAML file to your apessentials project.

•

Use Anypoint Studio and APIkit to generate a RESTful web service interface from a RAML file.

•

Test the web service in the APIkit Consoles view and a browser.

Add the RAML file
1. Drag the mua.raml file into the src/main/api folder in your apessentials project.

234

Create a RESTful interface
2. Right-click the RAML file and select APIkit > Generate Flows.

Note: If Generate Flows is disabled, there is an error in your RAML file and you need to return to
API Designer and fix it and then re-add it to Anypoint Studio.
3. Wait until a new mua.xml file is generated and opened.

235

Modify the HTTP endpoint
4. In mua.xml, double-click the HTTP connector in the mua-main flow.
5. Look at the path.
6. Click the Edit button next to Connector Configuration.
7. In the Global Element Properties dialog box, view the host and port values and click OK.
8. Change the connector configuration to the existing HTTP_Listener_Configuration.
9. Switch to the Global Elements view.
10. Select the mua-httpListenerConfig element and click Delete.
11. Return to the Message Flow view.

Examine the APIkit router
12. Double-click the APIkit Router.
13. In the APIkit Router Properties view, see the router configuration is set to mua-config.
14. Click the Edit button next to Connector Configuration.

15. In the Global Element Properties dialog box, look at the values and then click OK.

236

Look at the generated resource flow
16. Look at the name of the other flow created: get:/flights/{destination}:mua-config.

17. Double-click the Set Payload transformer and look at the value.

18. Switch to the Configuration XML view and look at the generated code.

Test the web service in the APIkit Consoles view
19. Run the application.
20. Look at the APIkit Consoles view that opens.

Note: If the API is not displayed in the APIkit Console, change your HTTP Listener Configuration
host from 0.0.0.0 to localhost.
21. Click the GET button for /flights/{destination}.
22. Click the Try It button.
23. Enter a destination of LAX (or any other value).
237

24. Click in the airline query parameter field and select one of the enumerated values, like delta.
25. Click the GET button; you should see the example data displayed.

Test the web service in a browser
26. Go to a browser, and make a request to http://localhost:8081/api/flights/LAX (or any other
destination); you should see the example data returned.

238

Walkthrough 10-4: Use Anypoint Studio to implement a RESTful
web service
In this walkthrough, you will wire the RESTful web service interface up to your back end logic. You will:
•

Split the getFlightsFlow into two flows: one that transforms the form post data into a
FlightRequest object and the other that gets all the flights.

•

Determine how to reference the web service destination and airline values.

•

Call the backend flow.

•

Test the web service in the APIkit Consoles view and a browser.

Modify the existing flows
67. Return to getFlights.xml.
68. Drag out a Flow scope element from the palette and drop it at the top of the canvas.
69. Give it a display name of getFlightsFromFormFlow.
70. Drag the HTTP endpoint from getFlightsFlow and drop it in the source section of
getFlightsFromFormFlow.
71. Drag the JSON to Object transformer from getFlightsForm and drop it in the process section of
getFlightsFromFormFlow.
72. Drag out a Flow Reference component from the palette and drop it in the process section of
getFlightsFromFormFlow.
73. In the Flow Reference Properties view, set the flow name to getFlightsFlow.

239

Determine how to reference the web service destination and airline values
74. Return to mua.xml.
75. Add a Logger to the get:/flights/{destination} flow.
76. Add a breakpoint to the Set Payload transformer in the get:/flights/{destination} flow.
77. Save all the files and debug the application.
78. Make a request to http://localhost:8081/api/flights/LAX.
79. In the Mule Debugger view, look at the inbound properties; you should see a query parameter
called airline with a value of all.

80. Click the Variables tab; you should see a variable called destination with a value of LAX.

81. Click the Resume button.

Call the backend flow
82. Return to the get:/flights/{destination} flow.
83. Add a Flow Reference component after the Set Payload transformer.
84. In the Flow Reference Properties view, set the flow name to getFlightsFlow.

240

Review the FlightRequest Java class
85. Open the com.mulesoft.training.FlightRequest.java class located in the project’s src/main/java
folder and examine the code.

Set the payload to a Java object with flight request data
86. Double-click the Set Payload transformer in the get:/flights/{destination} flow.
87. In the Properties view, set the value to a new instance of com.mulesoft.training.FlightRequest,
passing destination and message.inboundProperties.’http.query.params’.airline to it as
arguments.
Note: You can also copy this expression form the course snippets.txt file.

Test the web service in the APIkit Consoles view
88. Save the files and run the application.
89. In the APIkit Consoles view, click the GET button for /flights/{destination}.
90. Click the Try It button.

241

91. Enter a destination of LAX (or any other value) and click the GET button; you should now see
the real data (for LAX) displayed.

92. Scroll up in the /flights/{destination} resource window.
93. Set the airline query parameter to united.
94. Click the GET button; you see should now see only the flights for LAX on United.

Test the web service in a browser
95. Make a request to http://localhost:8081/api/flights/CLE; you should see data for all the flights to
CLE returned.

242

96. Make another request to http://localhost:8081/api/flights/PDX?airline=delta to retrieve flights for
PDX on Delta; ensure the correct data is returned.

243

Module 11: Deploying
Applications

In this module, you will learn:
•

About the options for deploying your applications.

•

What CloudHub is.

•

About when and how to use application properties.

•

(Optional) To deploy and run applications in the cloud.

•

(Optional) To deploy and run applications on-prem.

244

Walkthrough 11-1: Use application properties
In this walkthrough, you will introduce properties into your Mule application. You will:
•

Create a properties file for your application.

•

Create a Properties Placeholder global element.

•

Parameterize the HTTP Listener connector port.

•

Define and use Database connector properties.

Create a properties file
1. Right-click the src/main/resources folder in the Package Explorer and select New > File.
2. Name the file apessentials-dev.properties and click Finish.

Create a Properties Placeholder global element
3. Open global.xml.
4. Navigate to the Global Elements view and click Create.

245

5. In the Choose Global Type dialog box, select Component configurations > Property Placeholder
and click OK.

6. In the Global Element Properties dialog box, set the location to apessentials-dev.properties and
click OK.
Note: When setting the location, make sure you do not use a full path.

246

Parameterize the HTTP Listener port
7. Return to apessentials-dev.properties.
8. Create a property called http.port and set it to 8081.

http.port=8081	
  
9. Return to global.xml.
10. Double-click the HTTP Listener Configuration global element.
11. Change the port to the application property, ${http.port}.
12. Click OK.

Test the application
13. Save all the files and run the application.
14. Make a request http://localhost:8081/flights and confirm it still works.

247

Parameterize database credentials
15. Return to global.xml.
16. Double-click the MySQL Configuration global element to edit it.

17. Copy the host value and then click OK.
18. Return to your properties file and create a property called db.host and paste the value you
copied.
19. Create additional properties for the database port, user, password, and database values.

20. Save the file.

248

21. Return to the MySQL Configuration global element and replace the hard-coded configuration
parameters with property placeholders.

22. Test the connection and make sure it still works.
23. Click OK.

Test the application
24. Save the file and run the application.
25. Make a request http://localhost:8081/flights and confirm it still works.

Note: If you have time, also parameterize your Salesforce credentials and your HTTP Request
properties.

249

Walkthrough 11-2: Dynamically specify property files
In this walkthrough, you will set the property file to use dynamically. You will:
•

Define an environment property value in mule-app.properties.

•

Use the environment property in the Property Placeholder.

Define an environment property value in mule-app.properties
1. Open mule-app.properties.
2. Define a property called env and set it to dev.
3. Save the file.

Use the environment property in the Property Placeholder
4. Return to global.xml.
5. Double-click the Property Placeholder to edit it.
6. In the Global Element Properties dialog box, change the location to apessentials${env}.properties and click OK.

250

Test the application
7. Save all the files to redeploy the application.
8. Make a request http://localhost:8081/flights and confirm it still works and returns flights.

251

Walkthrough 11-3: (Optional) Deploy an application to the cloud
In this walkthrough, you will deploy your apessentials application to the cloud. You will:
•

Deploy an application to CloudHub from Anypoint Studio.

•

Run the application on its new, hosted domain.

•

View application data in CloudHub.

Access CloudHub
1. In a browser, go to http://anypoint.mulesoft.com and log in.

252

9. Click the CloudHub link in the main menu bar.

10. Look at the applications; for a new account, there will be no applications listed.

Deploy the application to CloudHub
11. Return to Anypoint Studio.
12. Select File > Export.
13. In the Export dialog box, select Mule > Mule Project to CloudHub.
Note: You can also right-click the project in the Package Explorer and select CloudHub >
Deploy to CloudHub.

14. Click Next.
15. In the login dialog box, enter your Anypoint Platform credentials.
16. In the Deploy to CloudHub dialog box, select apessentials as the project to deploy.

253

17. Wait while your credentials are used to successfully connect to the Anypoint Platform; once they
are, the environment drop-down will be populated based on your CloudHub settings.
18. Select an environment; you may or may not have more than one option.
19. Enter a domain name – the URL that will be used to access the application on CloudHub.
Note: Because the domain name must be unique across all applications on CloudHub, you may
want to use your last name or company name as part of the domain name, for example,
apessentials-{your_lastname}. The availability of the domain is instantly checked and you will
get a green check mark if it is available.
20. Set the Mule version to the version your project is using, like 3.7.0
Note: If you don’t know what version it is using, look at the Package Explorer and find a library
folder with the name of the server being used, like Mule Server 3.7.0. EE.
21. Look at the environment variables; you should see the env variable set to dev.

254

22. Click Finish.
23. Wait until you get a notice of a successful upload (or an error).

Find the application on CloudHub
24. Return to CloudHub and see your application listed.
25. If you see a blue circle next to the application name, wait until it turns green (or red).
Note: To follow the deployment process, mouse over the application name in CloudHub, select
Logs, and then watch the Live View of the Logs file.

Note: There will be a green circle next to the application if it was successfully deployed. There
will be a red circle next to the application if it was not. If your application did not successfully
deploy, mouse over its name in CloudHub, select Logs, and then examine the Logs to help
figure out why the application did not deploy. If you had errors when deploying, troubleshoot
them, fix them, and then redeploy.

Test the hosted application
26. Click the apessentials application in the application list on CloudHub; this takes you to the
Dashboard for the application.
27. Click the link to the application on its new domain: apessentials-{your_lastname}.cloudhub.io.
255

28. Click the link and then add the correct path, http://apessentials-lastname/flights; your application
should work as before but now it is running on CloudHub.

Note: You can also test your other endpoints: http://apessentials-lastname/sfdc and
http://apessentials-lastname/api/flights/SFO,

Explore application data on CloudHub
29. Return to CloudHub; you should see your application listed.

256

30. Click the application and then click the Manage Application button that appears on the right
side.
31. Click settings in the left-side menu.
32. Change the worker size to 0.1 vCores.

33. Click Properties; you should see your env environment variable and its current value.

257

34. Click Application Data in the left-side menu; you should see your watermark variable.

35. Click Schedules in the left-side menu; you should see the application poll and its current
schedule.
36. Click the Disable button.

258

Walkthrough 11-4: (Optional) Deploy an application on-prem
In this lab, you will deploy your application to a local, standalone Mule runtime. You will:
•

Package an application as a Mule deployable archive.

•

Start a local, standalone Mule runtime and Mule Management console (MMC).

•

Deploy an application to the Mule runtime.

•

Run the application.
Note: To complete this walkthrough, you need a standalone Mule runtime with Mule
Management Console (MMC). If you have not already downloaded this bundle, refer to the
setup instructions to get it.

Package the application
1. Return to Anypoint Studio and run the application to make sure it is working.
2. Click the red Terminate button to stop the embedded Mule runtime; YOU MUST DO THIS.
3. Select File > Export.

259

4. In the Export dialog box, select Mule > Anypoint Studio Project to Mule Deployable Archive and
click Next.
Note: You can also right-click a project in the Package Explorer and select Export > Anypoint
Studio Project to Mule Deployable Archive.

5. In the Export Mule Project dialog box, set the project to apessentials.
6. Browse to a location (like your desktop) and save the file as apessentials.

260

Set the environment property in the Mule wrapper.conf file
7. Locate the mmc-distribution-mule-console-bundle-{version}.zip you downloaded for class as
instructed in the setup instructions.
8. Unzip the file into some directory.

9. Navigate to the mmc-distribution-mule-console-bundle-3.7.X/mule-enterprise-3.7.X/conf folder.
10. Open wrapper.conf in a text editor.
11. Locate the last numbered wrapper.java.additional instruction near the top of the file.
12. Beneath it, create a new instruction with the number incremented by one that passes an
argument called env equal to dev to the runtime when it starts.

wrapper.java.additional.15=-­‐Denv=dev	
  	
  
Note: Be sure to use the correct number. This number may be different than shown here for
your version of the runtime.

261

13. Save the file.

Start the Mule runtime
14. On your computer, open a Terminal or Command window.
15. Change to the /mmc-distribution-mule-console-bundle-3.7.X/mule-enterprise-3.7.X/bin directory.
16. Run the mule script: mule (Unix) or mule.bat (Windows).

17. Wait until you see a message that Mule is up and kicking.
Note: You may need to scroll up to see this if you get a lot of DNS warnings after it.

Start MMC
18. On your computer, open a second Terminal or Command window.
19. Change to the /mmc-distribution-mule-console-bundle-3.7.X/mmc-3.7.X/apache-tomcat7.0.52/bin directory.
20. Run the startup script: ./startup.sh (Unix) or startup.bat (Windows).

262

21. Wait until you see a message that Tomcat started in your console.

22. In a browser window, navigate to http://localhost:8585/mmc-3.7.0.
Note: Change the URL as necessary for a different version of the runtime.
23. Enter a username and password of admin and click Login.

Register the Mule runtime in MMC
24. In MMC, click the Servers tab.
25. Look at the All group and see if it has a number of 1 and a server registered.

263

26. If All is 0 and there is an Unregistered server, select it in the list, and click the Register button.
Note: If the runtime does not register, follow the instructions in the next step.

27. If All is 0 and Unregistered is 0, add and register the server as follows:
•

Click the Servers tab.

•

Click the Add drop-down menu and select New Server.

•

Enter a server name of Max.

•

Leave the Mule Agent URL as http://localhost:7777/mmc-support

•

Click Add.

264

Deploy your application to the Mule runtime
28. Click the Deployments tab.
29. Click the New button.
30. Enter a deployment name of apessentials.
31. Select the server you just registered, Mule-3.7.X or Max.
32. Click the Upload New Application button.
33. Click the Browse button, browse to the zip file you created earlier, and click Open.
34. Click the Add button; you should see your archive listed.

265

35. Click the Deploy button in the lower-right corner; you should see your application appear in the
deployment list with a green circle next to it.

Note: If there is a red circle next to the application name, it was not deployed. Examine the log
files to figure out why it failed. Return to the mmc-distribution-mule-console-bundle-3.7.X/muleenterprise-3.7.X folder and open the logs folder. Open the mule-app-apessentials-{version}.log
file and locate the error. Fix the errors, create a new deployable archive if necessary, and then
redeploy the app in MMC.

Test the application
36. Make a request to http://localhost:8081/flights and find flights; your application should work as
before but now it is running on your local standalone Mule runtime.

266

37. Make a request to http://localhost:8082/api/flights/SFO; you should get flight results.

Stop MMC and the Mule runtime
38. Return to the MMC Terminal/Command window.
39. Run the shutdown script: ./shutdown.sh (Unix) or shutdown.bat (Windows).
40. Close the Terminal/Command window.
41. Return to the Mule Terminal/Command window.
42. Stop the server by pressing Ctrl+C.
43. Wait until the runtime stops.

44. Close the Terminal/Command window.

267



Source Exif Data:
File Type                       : PDF
File Type Extension             : pdf
MIME Type                       : application/pdf
PDF Version                     : 1.7
Linearized                      : Yes
Create Date                     : 2015:08:07 21:24:46Z
Creator                         : Word
Modify Date                     : 2015:08:07 14:25:54-07:00
XMP Toolkit                     : Adobe XMP Core 5.6-c015 81.157285, 2014/12/12-00:43:15
Creator Tool                    : Word
Metadata Date                   : 2015:08:07 14:25:54-07:00
Keywords                        : 
Producer                        : Mac OS X 10.10.2 Quartz PDFContext
Format                          : application/pdf
Title                           : Microsoft Word - APEssentials3.7_studentManual.docx
Document ID                     : uuid:51bd7ca3-c776-3145-b6d5-9da99038d502
Instance ID                     : uuid:e9506a9a-5783-ed4d-8910-e3b8b3e71409
Page Count                      : 267
EXIF Metadata provided by EXIF.tools

Navigation menu