Daniel Harfleet: Debugging Flex and Java at the same time

« Passing complex parameters and results | Main | A more secure ServiceLocator »

August 04, 2006

Debugging Flex and Java at the same time

Those of you are familiar with the java debugger in Eclipse will be pleased to know that Flex Builder includes a very similar debugger for debugging Flex code. In this article I will show you how to achieve end to end debugging, using Flex Builder, the FDS gateway logs and Eclipse java debugger connecting to JBoss by way of JPDA remote debugging.

As mentioned previously, the gateway is the component which lives on the server and is responsible for converting object instances between java and ActionScript. It can carry out deep copies and knows which java objects map to your Actionscript objects, assuming you have marked them with

[RemoteClass(alias="java.package.structure.classname")]

We can change the log level of the gateway and take a look at what it is up to.

In services-config.xml, change the log level from Error to Debug as below:


<logging>
<target class="flex.messaging.log.ConsoleTarget" level="Debug">


You will now have to restart JBoss. Now load up the app in your browser, also have the JBoss console on your screen, enter an address into the form and submit.
You will see the output of the 'request' in the console:

The output below occurs the first time a call is made from the client, it's just checking that the endpoint is still available, don't expect to see this every call.


12:16:14,805 INFO [STDOUT] [Flex] Deserializing AMF/HTTP request
Version: 3
(Message #0 targetURI=null, responseURI=/1)
(Array #0)
[0] = (Typed Object #0 'flex.messaging.messages.CommandMessage')
operation = 5
messageRefType = null
correlationId = ""
messageId = "8DA9ED25-7DA2-0175-16F8-5D4D2EF8E163"
headers = (Object #1)
timestamp = 0
body = (Object #2)
clientId = null
destination = ""
timeToLive = 0
12:16:14,837 INFO [STDOUT] [Flex] Serializing AMF/HTTP response
Version: 3
(Message #0 targetURI=/1/onResult, responseURI=)
(Typed Object #0 'flex.messaging.messages.AcknowledgeMessage')
destination = null
headers = (Object #1)
correlationId = "8DA9ED25-7DA2-0175-16F8-5D4D2EF8E163"
messageId = "2FC970B5-9518-4649-21E9-ED57D3A627EC"
timestamp = 1.152616574821E12
clientId = "2FC970B5-950E-1903-993A-5EB4299C54B5"
timeToLive = 0.0
body = null

Next you will see our request to the remote object:


12:16:14,852 INFO [STDOUT] [Flex] Channel endpoint my-amf received request.
12:16:14,868 INFO [STDOUT] [Flex] Deserializing AMF/HTTP request
Version: 3
(Message #0 targetURI=null, responseURI=/2)
(Array #0)
[0] = (Typed Object #0 'flex.messaging.messages.RemotingMessage')
operation = "addAddress"
source = null
messageId = "D9F1547F-D5A7-4C11-E53D-5D4D2ED818F1"
headers = (Object #1)
DSEndpoint = "my-amf"
timestamp = 0
body = (Array #2)
[0] = (Typed Object #3 'fdsweb.AddressVO')
line2 = "The Street"
line1 = "44"
postalCode = "EH11 9DQ"
city = "EDINBURGH"
clientId = null
destination = "addressBookDelegate"
timeToLive = 0

Remember that the data does not get transmitted in textual format, it gets sent in binary AMF, this is just the output from the gateway logging after it has received it.

Next we see the gateway calling the remote object and the results from that call:

12:16:14,868 INFO  [STDOUT] [Flex] Adapter 'java-object' called 'fdsweb.AddressB
ookDelegate.addAddress(java.util.Arrays$ArrayList (Collection size:1)
  [0] = fdsweb.AddressVO
    postalCode = EH11 9DQ
    line1 = 44
    line2 = The Street
    city = EDINBURGH

)'



12:16:14,868 INFO [STDOUT] [Flex] Result: 'java.util.Vector (Collection size:1)

[0] = fdsweb.AddressVO
postalCode = EH11 9DQ
line1 = 44
line2 = The Street
city = EDINBURGH

)'

And finally we see the response about to go back to the client:

12:16:14,868 INFO  [STDOUT] [Flex] Serializing AMF/HTTP response
Version: 3
  (Message #0 targetURI=/2/onResult, responseURI=)
    (Typed Object #0 'flex.messaging.messages.AcknowledgeMessage')
      destination = null
      headers = (Object #1)
      correlationId = "D9F1547F-D5A7-4C11-E53D-5D4D2ED818F1"
      messageId = "2FC97128-541C-9D37-38F6-21D302743239"
      timestamp = 1.152616574868E12
      clientId = "2FC97128-540D-3181-BC10-60C5D327A94E"
      timeToLive = 0.0
      body = (Externalizable Object #2 'flex.messaging.io.ArrayCollection')
        (Array #3)
          [0] = (Typed Object #4 'fdsweb.AddressVO')
            postalCode = "EH11 9DQ"
            line1 = "44"
            line2 = "The Street"
            city = "EDINBURGH"

The flex debugging provided in Eclipse is very similar to the java debugging and is intuitive for anyone who has ever used the java debugger. For the full details on debugging in Flex Builder, see the docs, for now you are good to go if you can just set a breakpoint as in the java debugger.

If you want to debug the remote object running in JBoss, you can set up JPDA (Java Platform Debugger Architecture). This allows Eclipse to connect to JBoss by way of sockets and exchange debugging information necessary for the java debugger.

Setting up JPDA in JBoss is actually very simple, all you need to do is:

a) stop JBoss
b) copy the [jboss root]/bin/run.bat to [jboss root]/bin/run_debug.bat (Unix/Linux users change as necessary)
c) in run_debug.bat, uncomment this line:


rem JPDA options. Uncomment and modify as appropriate to enable remote debugging.
rem set JAVA_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=y %JAVA_OPTS%

to read this:

rem JPDA options. Uncomment and modify as appropriate to enable remote debugging.
set JAVA_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=y %JAVA_OPTS%

d) start JBoss using your new run_debug script
e) in Flexbuilder/Eclipse, click on the 'bug' icon and select 'Debug....'
f) select 'Remote Java Application' and hit 'new', change the name of the configuration if you wish, change the port to 8787 (or change the connection properties to reflect those set in the run_debug script if different from above).
g) click debug
h) in the AddressBookDelegate source, add a breakpoint in the addAddress method
i) open the app in your browser and submit an address, you may need to press 'continue' if you do not reach the breakpoint straight away.

From the above techniques, you should be able to set a breakpoint in the Flex code and the java code and watch the gateway debug output, this will give you end to end debugging.

Posted by dharfleet at August 4, 2006 05:19 PM

Comments

Enjoyed browsing through the site

Posted by: katalog at September 28, 2006 01:37 PM

I got an error message... Failed to connect to Remote VM. Connection Refused.

Any clues?

Posted by: Tom Raic at November 20, 2006 02:54 PM

One thing I'm confused about: I'm remote debugging onto the same JBoss server I'm developing on. Issue I'm facing is that when I restart by JBoss server, it's listening for port 8787, prior to starting, and it doesn't continue starting. So when I turn debug mode on, the server jumps out of the listener, and continues running, and I get a connection refuse tryign to debug again. Is there a way to debug Flex and Java without remote debugging... just by using the internal debugger?

Posted by: Tom Raic at November 20, 2006 04:25 PM

Nevermind, I got it working. However, I can't seem to debug both Flex and Java at the same time. It's either one or the other.

Any clues?

Posted by: Tom Raic at November 20, 2006 08:22 PM

How is the best way to work with Java and FDS. I want to deploy my application on JBoss server and I need debug features and hotdeploy, etc, etc.

Posted by: Edgar Rivera at November 22, 2006 12:16 PM