Everyware™ Software Framework

<<Previous     Quickstart     Next>>

PART 3. ESF CODE EXAMPLES
Remote Debugging

 

Example

·         Overview

·         Prerequisites

·         Remote Debugging

Example

 

Overview

This howto shows how to start the remote debugger in Eclipse to attach to ESF.  It will also show how to do some basic debugging using the remote debugger.

 

In this example you will learn how to:

           

Prerequisites

 

Remote Debugging

Before we can begin remote debugging we need something to debug.  Start by creating a project with the following basic configuration

 

 

Below is the Activator code for this project.

 

package com.esf.example.debug.bundle;

 

import org.eclipse.soda.sat.core.framework.BaseBundleActivator;

 

import com.esf.core.logger.service.IEsfLoggerService;

import com.esf.example.debug.DebugExample;

 

public class Activator extends BaseBundleActivator {

 

      DebugExample debugExample = null;

     

      public void activate() {

            debugExample = new DebugExample();

            debugExample.bind(getIEsfLoggerService());

      }

     

      public void deactivate() {

            debugExample.unbind();

            debugExample = null;

      }

     

      private IEsfLoggerService getIEsfLoggerService() {

            return (IEsfLoggerService) getImportedService(IEsfLoggerService.SERVICE_NAME);

      }

     

      protected String[] getImportedServiceNames() {

            return new String[] {

                  IEsfLoggerService.SERVICE_NAME

            };

      }

}

 

This is a pretty standard and simple Activator.  Now we can look at the main implementation class.  This is shown below.

 

package com.esf.example.debug;

 

import org.soda.stepstone.core.Delay;

import org.soda.stepstone.core.IWork;

import org.soda.stepstone.core.Worker;

 

import com.esf.core.logger.service.IEsfLoggerService;

 

public class DebugExample {

 

      private static final String LABEL = "com.esf.example.debug.DebugExample: ";

     

      private IEsfLoggerService esfLoggerService;

     

      private Worker exampleWorker;

      private long startTime;

     

      public void bind(IEsfLoggerService esfLoggerService) {

            this.esfLoggerService = esfLoggerService;

            startTime = System.currentTimeMillis();

           

            // Create worker thread

            exampleWorker = new Worker("Example Worker Thread", new IWork() {

                  public boolean doWork() throws InterruptedException {

                        return doExampleWork();

                  }

            });

            exampleWorker.start();

      }

     

      public void unbind() {

            exampleWorker.stop();

            exampleWorker = null;

            esfLoggerService = null;

      }

     

      private boolean doExampleWork() {

            long currentTime = System.currentTimeMillis();

           

            if((currentTime + 5000) < startTime) {

                  esfLoggerService.logInfo(LABEL + "We've been up for 5s - killing the thread");

                  return false;

            } else {

                  esfLoggerService.logInfo(LABEL + "We've not been up for 5s yet");

                  Delay.seconds(1);

                  return true;

            }

      }

}

 

This is a simple class with the standard bind() and unbind() methods.  Also, we use a Stepstone Worker to do our thread work.  The Worker class is a handy class to use when starting threads.  It prevents the need to handle all of the standard synchronization that should normally be done when dealing with threads.  The core of the usage is the ‘doWork’ method which is the ‘doExampleWork’ method in our example.  Once the Worker is started this method is called.  So long as it returns true and the worker has not been stopped, it will be called again.  If it returns false or it is stopped, it will stop running until it is started again.

 

There is an intentional bug in this class.  However, don’t worry at this point about finding it as we’ll use the remote debugger to do so.

 

Note once the class is fully written you must remember to set the Activator and update the manifest with the proper dependencies.  It is easy to forget these steps.  This is shown if figures one and two.

 

Figure 1 Adding the Activator to the Manifest

 

Figure 2 Adding the Required Dependencies to the Manifest

 

This is the output after placing the exported bundle into the /etc/jvm/esf/dropins/ directory and starting ESF.

 

root@localhost:/opt/jvm/esf> ./start_equinox.sh

 

osgi> [INFO] Junit Extender starting ...

[INFO] 2010-07-29 17:12:20.384 - com.esf.example.debug.DebugExample: We've not been up for 5s yet

[INFO] 2010-07-29 17:12:21.395 - com.esf.example.debug.DebugExample: We've not been up for 5s yet

[INFO] 2010-07-29 17:12:22.395 - com.esf.example.debug.DebugExample: We've not been up for 5s yet

[INFO] 2010-07-29 17:12:23.396 - com.esf.example.debug.DebugExample: We've not been up for 5s yet

[INFO] 2010-07-29 17:12:24.397 - com.esf.example.debug.DebugExample: We've not been up for 5s yet

[INFO] 2010-07-29 17:12:25.397 - com.esf.example.debug.DebugExample: We've not been up for 5s yet

[INFO] 2010-07-29 17:12:26.398 - com.esf.example.debug.DebugExample: We've not been up for 5s yet

[INFO] 2010-07-29 17:12:27.399 - com.esf.example.debug.DebugExample: We've not been up for 5s yet

[INFO] 2010-07-29 17:12:28.399 - com.esf.example.debug.DebugExample: We've not been up for 5s yet

[INFO] 2010-07-29 17:12:29.400 - com.esf.example.debug.DebugExample: We've not been up for 5s yet

[INFO] 2010-07-29 17:12:30.401 - com.esf.example.debug.DebugExample: We've not been up for 5s yet

[INFO] 2010-07-29 17:12:31.403 - com.esf.example.debug.DebugExample: We've not been up for 5s yet

[INFO] 2010-07-29 17:12:32.404 - com.esf.example.debug.DebugExample: We've not been up for 5s yet

[INFO] 2010-07-29 17:12:33.404 - com.esf.example.debug.DebugExample: We've not been up for 5s yet

 

Clearly we have been running for more than five seconds – yet the thread continues to run.  So, we need to find the bug.  Start by Clicking ‘Window -> Open Perspective -> Other’ and then select ‘Debug’ as shown in figure 3.

 

Figure 3 Opening the Debug Perspective

 

Now open the /opt/jvm/esf/start_equinox.sh script.  Add the highlighted line below.

 

###########################################################

#!/bin/sh

 

export PATH=$PATH:/opt/jvm/bin

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/jvm/bin

 

j9 -Dorg.eclipse.soda.sat.core.util.logLevel=WARNING \

                -debug:transport=dt_socket,server=y,address=8096 \

                -Declipse.ignoreApp=true \

                -jar org.eclipse.osgi_3.4.0.v20080605-1900.jar \

                -console –clean

###########################################################

 

This configures j9 to listen on port 8096 and wait to start the full VM until the Eclipse debugger attaches.  You’ll note now when you run start_equinox.sh – nothing happens.  So, we need to configure Eclipse to connect.  In Eclipse, go to ‘Run -> Debug Configurations’.  This will open the dialog box in figure 4.

 

Figure 4 Creating a Debug Configuration

 

Select ‘Remote Java Application’  by right clicking on it and selecting ‘New’.  This will open the dialog in figure 5.

 

Figure 5 Setting up the Debug Configuration

 

On the remote target run these commands:

cd /opt/jvm/esf

./start_equinox.sh

 

Now enter in the host (remote target) IP address, port 8096, click ‘Apply’, and then ‘Debug’.  You should now see something similar to figure 6.

 

Figure 6 Debugging

 

You can see in the upper left highlighted section that the execution is paused at line 40 of the DebugExample.java class.  This is the case because we have set a breakpoint by double clicking in the lower left highlighted area so a blue dot appears.  This sets the breakpoint.  You can also see in the upper right highlighted section what the values are of these two variables in question.  We are looking at this statement because this is obviously where the error has to be.  Figure 7 shows how to resume execution and shows the updated values for startTime and currentTime when we hit the break point again.

 

Figure 7 More debugging

 

Note the time has moved far more than 1s because we are in control of the execution of the thread.  So, the code is running only as fast as we click the resume (F8) button.  By looking at the statement below we can see there is a problem.

 

if((currentTime + 5000) < startTime) {

 

Clearly this will not work properly.  It must be changed to:

 

if((startTime + 5000) < currentTime) {

 

Note if we make this change in the debug editor it immediately takes effect in our debug session.

 

With the bug fixed we can terminate the existing debug session, export the bundle, and copy it to the target.  Then you can either run another debug session or run in standard mode by removing the debug listener line from the start_equinox.sh script.  Shown below is the now properly functioning output.

 

root@localhost:/opt/jvm/esf> ./start_equinox.sh

 

osgi> [INFO] Junit Extender starting ...

[INFO] 2010-07-29 17:52:24.001 - com.esf.example.debug.DebugExample: We've not been up for 5s yet

[INFO] 2010-07-29 17:52:25.002 - com.esf.example.debug.DebugExample: We've not been up for 5s yet

[INFO] 2010-07-29 17:52:26.003 - com.esf.example.debug.DebugExample: We've not been up for 5s yet

[INFO] 2010-07-29 17:52:27.004 - com.esf.example.debug.DebugExample: We've not been up for 5s yet

[INFO] 2010-07-29 17:52:28.004 - com.esf.example.debug.DebugExample: We've not been up for 5s yet

[INFO] 2010-07-29 17:52:29.005 - com.esf.example.debug.DebugExample: We've been up for 5s - killing the thread

 

If you don’t want to create this entire project from scratch the code (‘unfixed’) can be downloaded here.  You can use this procedure to install it.

 

<<Previous     Quickstart     Next>>

 

Copyright © 2010 Eurotech Inc.  All rights reserved.