Testing and Debugging

This section discusses how you can use the seamless IDE integration of the UltraESB to test, debug and fix the solution that you develop before deploying it on production or even in integration environment. With almost all the other ESBs testing a solution will require you to build the artifact and deploy it on an integration environment to test it. This process leads to a major drawback of the software testing theories. In software engineering, the modern software life-cycle contains 2 phases of testing as follows;

  1. Developer testing (White-Box testing) - to make sure the solution that you develop works at least on the proper flow

  2. Integration testing (Black-Box testing) - to make sure that the solution delivers what it meant to be, on an environment which is nearly equal to that of the target production environment and the testing of the exception flows.

While the integration testing (quality assurance) of-course needs an integration environment and a deployable artifact for testing, the developer testing just need to make sure that the functionality that the developers develop are correct. This is very close to writing unit tests for verifying the functionality that is being developed. This chapter mainly focuses on the developer testing and debugging of the solution within the IDE while the integration testing requires an integration environment and a deployment.

The rest of this documentation selects a sample solution and shows you how to run it within the IDE, test it, debug it and fix the issues if there are any to complete the development phase of the solution.

Sample Solution

The Solution Development section extensively describes how you can develop a solution, for this section we are going to select a sample solution that will help the explanation of the rest of the functionality testing and debugging.

This solution is a simple "hello-world" deployment unit with the configuration which consists of a proxy service, 2 endpoints and 2 sequences. The following code segments shows the ultra-unit.xml file with the sample configuration that we are going to use in the testing and debugging.

Sample deployment unit configuration

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:u="http://www.adroitlogic.org/ultraesb"
  xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.adroitlogic.org/ultraesb http://schemas.adroitlogic.org/ultraesb/v2_6/ultraesb-artifacts.xsd">

  <u:proxy id="MyFirstProxy">
    <u:transport id="http-8280"/>
    <u:target inSequence="MyFirstSequence" inDestination="MyFirstEndpoint">
      <u:outSequence>
        <u:java><![CDATA[
          System.out.println("Reply payload : " + mediation.readPayloadAsString(msg));
        ]]></u:java>
      </u:outSequence>
      <u:outDestination>
        <u:address type="response"/>
      </u:outDestination>
    </u:target>
  </u:proxy>

  <u:endpoint id="MyFirstEndpoint">
    <u:address>http://localhost:9000/service/EchoService</u:address>
  </u:endpoint>

  <u:sequence id="MyFirstSequence">
    <u:class name="sample.SimpleJavaMediation1"/>
  </u:sequence>

</beans>

The above configuration contains a proxy service named "MyProxyService" with the in sequence of the proxy service being referred to a defined sequence with the identifier "MyFirstSequence", in destination referred to a defined endpoint with the identifier"MyFirstEndpoint", the out sequence and out destination both in-lined as a Java fragment sequence and a response type endpoint respectively.

The sequence "MyFirstSequence" has been defined as a byte code sequence, referring to the class with a fully qualified class name "sample.SimpleJavaMediation1", a sample byte code sequence shipped with UltraESB, of which the source can be found under the conf > mediation > src > java file path in the UltraESB installation home.

Adding your own sequence class
Your own byte code sequence can also be referred as in the sample class that we used for the configuration, in which case you need to add the source file of that class in addition to the binary file into the UltraRuntime project, as we are going to use the IDE to test and debug this solution.

You may follow the guide with this configuration, in which case you need to copy this configuration and replace the content of your ultra-unit.xml or use your own developed deployment unit configuration and map the relevant sections to your configuration in following the guide.

Running the Solution

For running the UltraESB with the above configuration or the configuration you developed in the deployment unit, there is a built in UltraESB runtime configuration. This profile loads the content from the standard conf directory so any deployment units will be loaded and installed at startup apart from the ultra-root.xml configuration.

Switch to the UltraESB runtime configuration as shown below (1) and run it (2) to run the ESB with the given configuration.

running

When you click on the Run button on the top tool bar, you will be able to see the Run panel in the bottom of the window as follows, with the console log written into the panel.

run pane

That is just what you need to do to run the solution you developed, regardless of the fact whether you have sequences/endpoints in-lined or referred and the sequences could be bytecode, Java fragments or whatever the  types, etc.. This makes it easy to run the solution while developing and it drops the development time drastically as you are just on the IDE and no need to start the ESB separately or deploy the solution to test in on a separate location.

Testing the Solution

Now that the solution that we have been developing is running, we can test it to see whether you see the expected behaviour from the complete application by sending a sample message through the running solution.

SOA Toolbox

For testing the solution, the SOA Toolbox can be used, which supports many convenient tools. In this particular case we have to expose a service named "EchoService" running on the port 9000 on the localhost as the back-end service, and a client to invoke the proxy service in our solution. While you can use any mock service (depending on your requirement of the actual service and its behaviour, or even you could use the actual service that you are targeting to switch to at production if it is of no harm to test over it) to replace the back-end service emulated by the toolbox, we recommend using the SOA Toolbox as the client.

SOA Toolbox supports many advance features for sending sample test messages emulating slow connections etc.. which make it really usable for testing the solution. The complete guide on the SOA Toolbox helps you understand the advance features of the Toolbox and how to use those.

Start the toolbox shipped in with the UltraESB to spin a server and a client to invoke this solution and test it.

In Unix based systems, navigate to the "bin" directory of the UltraESB installation, using a console.

$ cd /opt/ultraesb-2.6.1/bin
$ ./toolbox.sh

On Windows based systems, use the file explorer to navigate to the "bin" directory of the UltraESB installation and double click on the "toolbox.bat" file to launch the Toolbox.

Running the back-end service

SOA Toolbox ships with a service named "EchoService" configured to deploy on Jetty Server, so we are going to run that service as the back-end service for this illustration on testing the solution.

Click on the "File" menu and select New > Jetty Server from the cascading menu or alternatively the Ctrl+J shortcut key to create a new Jetty Server instance which hosts the sample services used by UltraESB.

toolbox jetty server menu

Now you should see the Jetty Server panel tab on the Toolbox application. Click on the "Start Jetty" button on the top of the pane just after the port as shown below by (1), to start the Jetty Server with the sample EchoService hosted on it;

toolbox jetty server pane scaled

You should see the Start Jetty button as a disabled button and the Stop Jetty button as an active button, once the sample Jetty server has completed starting. Once it is started, the EchoService on port 9000 having the service URL http://localhost:9000/service/EchoService should be ready.

Invoking the proxy via the client

Next we use the HTTP/S client of the Toolbox to invoke the proxy service that we have developed.

Click on the "File" menu and select New > HTTP/S Client from the cascading menu or alternatively the Ctrl+C shortcut key to create a new HTTP/S Client instance which can be used to post any HTTP/S message.

toolbox http client menu ug

Now you should see the HTTP/S Client panel tab on the Toolbox application. Using this client application we can invoke the proxy service that we have developed in our solution. To invoke the proxy service, follow the steps given below, and the respective action on the screen shot.

  1. Type the URL of the invoking service to be "http://localhost:8280/service/MyFirstProxy".

  2. Check the HTTP method on the right side of the URL to be "POST" meaning that we are going to do a HTTP POST request to the given URL.

  3. Then select the HTTP message body to be sent to the service. There are 4 pre-sets available out of which we are going to use the first one, so click on the "1" pre-set message body.

  4. Observe the message body filled in with the pre-set message 1 on the request pane

  5. Click on the "Send" button in the middle of the request and response panes to invoke the proxy service with the given message body.

  6. On the response pane you should be able to see the response, if the proxy is working from an external users point of view

client invoke

While this confirms the fact that the proxy service is working, we might want to verify the console output to see the print-lines that we have on the mediation to be invoked properly. If you look at the run panel on the bottom of the IDE you will be able to see the print-lines on the output as follows;

run pane2

Now if you need to change some logic of the referred in sequence, the SimpleJavaMediation1 class or the in-lined out sequence, you can just change it on the IDE, stop the UltraESB using the Stop button stop on left most tools of the run panel and start it back again using the Rerun button rerun again on the same tools set. This makes it really easy to do the iterative development of the solution that you are developing, without wasting time ton the building and deployment.

For example lets assume that you want to print the message number received to this proxy in this session in the in sequence, we could edit the SimpleJavaMediation1.java source file from within the IDE and re-run the UltraESB on the same IDE to see that in effect.

Press Ctrl+N short cut key to open up a class and type "Simple" and select the SimpleJavaMediation1 from the drop down, and hit Enter to open the class.

open class

You could optionally use the project browser on the left hand pane to browse to the SimpleJavaMediation1.java file.

Now to print the message count add a print-line to the execute method as follows;

public void execute(Message msg, Mediation mediation) throws Exception {
  System.out.println("SimpleJavaMediation1 = Message target : " + msg.getDestinationURL());
  count++;
  System.out.println("SimpleJavaMediation1 = Message count : " + count);
}

Now stop the UltraESB and rerun it from the run panel. Send a message again from the Toolbox client to see the output on the IDE run panel, and you will be able to see the message count printed on the output.

Debugging the Solution

Debugging an integration solution developed with a typical ESB is pretty hard, most of them do not support step through debugging at all, it was like JavaScript earlier days, where you used to put alerts and debug. UltraESB on the other hand provides seamless step through debugging just as how you debug today’s JavaScript code within the browser itself or your simple Hello World Java application within the IDE.

Continuing our exercise on the previous section on testing the solution that you have developed, this section walks through debugging the solution and improving it.

There are 2 types of possible debugging scenarios, which belongs to the 2 testing categorizations.

Standalone IDE debugging

Debugging the solution as an standalone application within the IDE is pretty easy and is mostly used with developer testing, where the developer finds and issue in the testing phase which is not obvious to fix, and e/she want to see what is happening internally.

To be able to step through debug while testing the solution requires the UltraESB project to be started in debug mode within the IDE.

Note
Please make sure to stop the UltraESB if it is running in the run panel, otherwise you will get a bind exception for the ports when you try to debug, as it tries to start the UltraESB transports on the same ports.

In order to start the UltraESB with the solution that you developed in debug mode, you should use the Debug icon instead of the Run icon on the top tool-bar.

debug
  1. Note that the Debug icon on the right side of the Run icon on the top tool-bar, which we use to start the UltraESB in debug mode.

  2. Note the new addition of the Debug tab into the bottom panel which is going to be automatically active, when you start the server in debug mode.

Now the UltraESB is running in the debug mode, and before sending the sample message we should put the breakpoints into the code where we want to debug. For that matter you can click on the left bar of the source editor as shown below.

This case we want to debug the execute method of the sequence class SimpleJavaMediation1.java so lets put the breakpoint at the first line of the execute method.

break point

The breakpoint is now set and we are ready to debug a single message flow.

Breakpoints for startup
If the mediation sequence initialization (init method of the sequence class) or some UltraESB starup related point debugging, you should put the break points before starting the UltraESB in debug mode

Send a message using the Toolbox client to debug the message inside the sequence. The message will be paused at our breakpoint and the breakpoint will get highlighted.

debug active

Debugging an issue within the IDE is quite easy, and the following items explains all what you have to know about the IDE features in debugging.

  1. Note the highlighted breakpoint where the message execution is paused by the debugger

  2. The Variables pane in the debug panel shows you the states and the values of all the relevant variables in the context.

  3. Watches pane allows you to watch the value of a certain variable or an expression throughout the debug session, how it changes, etc..

  4. The execution call stack or the path which the thread came to this point is shown in the Frame pane, where you can see the states of the variables on that context.

  5. The debug actions tool-bar facilitates different mandatory actions, which we will discuss shortly in more detail

  6. Debug panel tool-bar facilitates many other debug operations and controls

  7. The Console tab when switched from Debugger tab, shows the runtime output.

While you can see the complete context in the Variables pane, sometimes it is necessary to see the values/results of an evaluated expression in this context to understand/point out certain logics. In which case the Evaluate Expression tool works like a charm.

Right click on the editor and select the "Evaluate Expression" menu item from the context menu to get the Evaluate Expression tool.

eval menu

The Evaluate Expression tool will appear on selecting this menu item and type the expression that you want to see the result as follows.

evaluate

The debug actions tool-bar gives a good set of controls to support step through debugging with certain shortcut keys.

Icon Shortcut Key Action

show current execution

Alt+F10

Shows the execution points

step over

F8

Step over to the next line

step into

F7

Step into the next immediate call

force step into

Alt+Shift+F7

Force step into the next immediate call

step out

Shift+F8

Step out to the immediate caller

drop frame

 

Drop frame (Reverse step)

run to cursor

Alt+F9

Run to cursor

While this action tool-bar is of utmost help, the debug panel tool-bar is also facilitating many required features

Icon Shortcut Key Action

continue

F9

Resume program

stop

Ctrl+F12

Stop debugging

pause

 

Pause program

re debug

Ctrl+F5

Re-debug program (after stopping)

view breakpoints

Ctrl+Shift+F8

View breakpoints

mute breakpoint

 

Mute breakpoints

All the above controls of the IDE and the seamless integration to use these IDE debugging features help UltraESB users to develop there solutions based on the UltraESB in a flash.

Remote debugging

Remote debugging only differs from the standalone debugging, in the way UltraESB is being started and the way the IDE is being connected to the server.

Remote debugging is important and useful in environment specific issues, where the same issue might not occur in the developers development environment. These issues are mostly being discovered in the black box testing on the integration environment. In these cases the UltraESB is started as usually with parsing few special flags to the JVM, for the IDE to be able to remotely debug the UltraESB server running on the integration environment.

UltraESB supports two approaches in starting an UltraESB instance.

Standalone startup script

When running the UltraESB with standalone startup script, the ultraesb.sh or ultraesb.bat files found in the bin directory of the UltraESB installation directory.

To be able to remote debug the server started with the startup script you should pass in the "-xdebug" flag to the script as follows.

$ cd /opt/ultraesb-2.6.1/bin
$ ./ultraesb.sh -xdebug

When you start the UltraESB with passing this option, you will see on the console that the UltraESB server is waiting for a remote debug connection to start as follows.

Starting AdroitLogic UltraESB ...
Using JAVA_HOME  : /opt/jdk1.7.0_80
Using ULTRA_HOME: /home/rajind/builds/ultraesb-2.6.1
Listening for transport dt_socket at address: 8000

Once you connect the IDE remote debugger to the host running the UltraESB server over port 8000, which is the default remote debugging port, you will be able to see the server starting up.

As a daemon with wrapper

To enable remote debugging when running as a daemon with wrapper, edit the wrapper.conf file located in the conf directory of the UltraESB installation directory and add the following additional java arguments to the next numbered additional arguments.

wrapper.java.additional.12="-Xdebug"
wrapper.java.additional.12.stripquotes=TRUE
wrapper.java.additional.13="-Xrunjdwp:transport=dt_socket,server=y,address=8000,suspend=y"
wrapper.java.additional.13.stripquotes=TRUE

Then we can start the UltraESB with the ultraesb-daemon.sh script found in the bin directory of the UltraESB installation but most probably when you run you will get an output as below.

No passwd entry for user 'ultraesb'

That is because before running a small change has to be made in ultraesb-deamon.sh.

Let’s open up the ultraesb-deamon.sh on a text editor. At the top there is an entry as USER=ultraesb. Now if you are running this under a user called ultraesb this is fine but if you are running under another user say "asankha" change this entry to USER=asankha. Now you can run it without any problem.

$ cd /opt/ultraesb-2.6.1/bin
$ ./ultraesb-daemon.sh console

You will be able to see the daemon script is blocking the startup until the remote debugger is connected.

Running AdroitLogic - UltraESB...
--> Wrapper Started as Console
------------------------------------------------------------------------
The JVM is being launched with a debugger enabled and could possibly be
suspended. To avoid unwanted shutdowns, timeouts will be disabled,
removing the ability to detect and restart frozen JVMs.
------------------------------------------------------------------------
Launching a JVM...
Listening for transport dt_socket at address: 8000

Once the IDE remote debugger is connected the server will resume the startup.

Connecting the IDE

In-order to connect the IDE to remote debugging, a remote debugging configuration needs to be created. For that matter click on the UltraESB runtime configuration and once you click on that you will see a drop-down menu as shown below.

edit config

There you will see at the bottom, a configuration as "UltraESB (Remote Debug)". You can simply use that as it has been already configured for you, but to understand it better let’s look at the configuration.

Click on the "Edit Configurations" to see the configuration editing window. There you can see a configuration under the "remote" section as shown below.

remote conf
  1. Name to identify the configuration, here we have used "UltraESB-Remote"

  2. Host name at which the UltraESB server is running, in this configuration we have used "localhost" assuming UltraESB server is running on the same machine

  3. Port has been set to "8000" which is the remote debug listening port specified in the UltraESB server running remotely.

  4. Module in this configuration is <whole project>. You can change the module or keep it as <whole project> if you have more than one module in your solution project to debug

Now when you click "OK" this "UltraESB (Remote Debug)" will be selected and you will notice that the Debug icon (re debug) enabled, while Run icon is disabled (as this configuration is only for remote debugging)

Click on the Debug button to attach to the remote UltraESB server.

Enable port 8000
If you are running the UltraESB server on a hardened system behind a firewall, you might want to unblock the port 8000 such that the IDE debugger can attach to the UltraESB.

Put a breakpoint as in the standalone case and send a message to the remote UltraESB server, where you will be able to debug that message flow from within your IDE with all the debug options in standalone mode applied exactly the same to the remote debugging session too.

Advance remote debug options

You can change the port from 8000 to any port available to use, by editing the ultraesb.sh/bat and replacing the 8000 in the following string. Same way you could change the port that you specify for the wrapper.conf

XDEBUG="-Xdebug -Xnoagent -Xrunjdwp:transport=dt_socket,server=y,address=8000"

You could change the behaviour of the debugger to not to suspend the startup by changing the above line to read as follows. Note the addition of suspend attribute. Same way with wrapper you can change the suspend value to "n" to not to suspend the server startup

XDEBUG="-Xdebug -Xnoagent -Xrunjdwp:transport=dt_socket,server=y,address=8000,suspend=n"
In this topic
In this topic
Contact Us