Tuesday, January 24, 2012

Tech : Extending PHPUnit for Data Driven testing

Testing for PHP?  Look no further then PHPUnit(http://www.phpunit.de).  This framework has all the spunk that junit provides for the java platform.

However once pushing onto a full team, I found things I liked about my homegrown testing platform written in Perl.  Perhaps we can take some of PHPUnit and adapt it for our needs?

However phpunit is so tightly integrated into JetBrain's PHPStorm and all the functionality it brings via test suites it be a pain to rewrite, especially for testing.  Luckily, the implementation was done in full OO form, so we can subclass the phpunit classes, since its fully OO.

Here's my additional requirements

R-1) For all test we want folders input, expected, output.   The former 2 are in version control which defines the test.  The later output, is generated for each test run.  When finished we want the outputs to be automatically compared to ExpectedOutput which is in version control.

The names of the folder are:
 
output/test_
input/test_
expectedoutput/test_

- is a unique test identifier, preferrably alphanumeric.
- is the name of your test.


R-2) The test cases to be NICELY formatted so all test and output are clearly reviewable.
{erformance, time and memory should be dumped after each test.  We can diff these runs over time to measure performance and memory impacts as well.
i.e.

 

BTST_Formatted_TestSuite::setUp()

+++++++++++++++++++++++++++++++++
------------------------------------------------
---------------Starting: 'test0a_enumerationException'  Date: '2012-01-24T22:57:04+05:30'
------------------------------------------------
    ***Memory at End: 12.917344 MB***

Date:  2012-01-24T22:57:05+05:30 
Duration:  0.037098169326782 
FINISHED with result: SUCCESS()
-------------------------------------------- 


R-3) All of this should be summed together into suite summary and reason of failure at the end for any cases
 
BTST_Formatted_TestSuite::tearDown()
****************************************************************************
**************** TestSuite BCOM_SegmentFormat_AllTests FAILED
****************
**************** Total Cases: 21
**************** Total Passes: 20
**************** Total Failed: 1
**************** Total Errors: 1
**************** Total Assertions: 114
**************** Total Time: 0.52025103569031 s
****************************************************************************
There was 1 failure:

1) Warning
Test method "test4bHelper" in test class "SegmentFormatTest" is not public.

Btst_Formatted_TestSuite.php:35

There was 1 error:

1) SegmentFormatTest::test5b_MsgGrpLoopbackOutOfOrderNominal
MultipleFirstSegmentTypeException: Recieved Multiple segments for first segType, abort queue 

/SomeFile1.php:615
/SomeFile1.php:712
/SomeFile2:468
/SomeFile3:35
E_CORE_WARNING: PHP Startup: Unable to load dynamic library '/usr/local/zend/lib/php_extensions/imagick.so' - libMagickWand.so.2: cannot open shared object file: No such file or directory
#0 Unknown


Time: 1 second, Memory: 16.75Mb

OK (0 tests, 0 assertions)

Okay so that is requirements.  How do we achieve this?
In section 19 of PhpUnit Manual (http://www.phpunit.de/manual/current/en/extending-phpunit.html), it discusses how to extend.



Okay now we have the design done, lets get to some design details

Figure 1: Static UML Diagram for PHPUnit DD

1) Btst_Framework_TestCase.  Here you must save the current name of the test and use that as per (R-1).  This class deals with providing generic functions like database loading for all your data. It also deals with getting the input/output/expected directories and comparing files in a folder.

 
/*
*
* Purpose of class is to allow expected results, inputs and outputs
* to be auto managed
*
*/
class Btst_Framework_TestCase extends PHPUnit_Framework_TestCase
{

    const INPUT_DIR = 'inputs';
    const OUTPUT_DIR = 'output';
    const EXPECTED_DIR = 'expectedoutput';
    
    protected $_fullUnitPath = NULL;
    
    protected $_buildExpectedInputPaths = false;
    
    public function getInputD()
    {
        if ( ! $this->_fullUnitPath )
        {
            throw new BsmsObjectNotInitialized("_fullUnitPath" . "\nPlease follow the Setup Before Class as per BtstStackTest");
        }
        $osCommands = new ButlOsCommands();
        $inputDir = $osCommands->joinPath($this->_fullUnitPath , self::INPUT_DIR);   
        $dir = $osCommands->joinPath($inputDir , $this->getName());
        
        return $dir;
    }
    
    public function getOutputD()
    {
        if ( ! $this->_fullUnitPath )
        {
            throw new BsmsObjectNotInitialized("_fullUnitPath" . "\nPlease follow the Setup Before Class as per BtstStackTest");
        }
        $osCommands = new ButlOsCommands();
        $inputDir = $osCommands->joinPath($this->_fullUnitPath , self::OUTPUT_DIR);   
        $dir = $osCommands->joinPath($inputDir , $this->getName());
        return $dir;
    }
    
    
    public function getExpectedD()
    {
        if ( ! $this->_fullUnitPath )
        {
            throw new BsmsObjectNotInitialized("_fullUnitPath" . "\nPlease follow the Setup Before Class as per BtstStackTest");
        }
        $osCommands = new ButlOsCommands();
        $inputDir = $osCommands->joinPath($this->_fullUnitPath , self::EXPECTED_DIR);   
        $dir = $osCommands->joinPath($inputDir , $this->getName());      
        return $dir;
    }
    
    
    //does a recusive rmdir
    public static function rrmdir($dir)
    {
        if (is_dir($dir))
        {
            $objects = scandir($dir);
            foreach ($objects as $object)
            {
                    $osCommands = new ButlOsCommands();
                    $filePath = $osCommands->joinPath($dir ,$object);              
                    if ($object != "." && $object != "..")
                    {
                        if (filetype($filePath) == "dir")
                        {
                            self::rrmdir($filePath);
                        }
                        else
                        {
                            unlink($filePath);
                        }
                    }
            }
            reset($objects);
            rmdir($dir);
        }
    }
    
    public static function setUpBeforeClassClearOutDir( $myUnitTestDir )
    {
    
        //@TODO:  Need to fix on windows before continuing.
        if ( ! $myUnitTestDir )
        {
            throw new BsmsObjectNotInitialized( $myUnitTestDir . "\nPlease follow the Setup Before Class as per BtstStackTest" );
        }         
        if ( ButlOsEnum::thisOS() == ButlOSEnum::LINUX() ||  ButlOsEnum::thisOS() == ButlOSEnum::MAC() || ButlOsEnum::thisOS() == ButlOSEnum::WINDOWS() )
        {
            $osCommands = new ButlOsCommands();
            $outdir = $osCommands->joinPath($myUnitTestDir, self::OUTPUT_DIR);
            if ( is_dir($outdir) )
            {
                self::rrmdir( $outdir);
            }
        }
    }
    
    
    
    
    protected function setUp()
    {
    
        //@TODO: Need to fix on windows before continuing.
        if ( ButlOsEnum::thisOS() == ButlOSEnum::LINUX() ||  ButlOsEnum::thisOS() == ButlOSEnum::MAC() ||  ButlOsEnum::thisOS() == ButlOSEnum::WINDOWS()  )
        {
            mkdir( $this->getOutputD(), 0775, true);
            
            if ( $this->_buildExpectedInputPaths)
            {           
                if (!is_dir($this->getInputD()) )
                {
                    mkdir( $this->getInputD(),   0775, true);
                }
            
                if (!is_dir($this->getExpectedD()) )
                {
                    mkdir( $this->getExpectedD(),  0775, true);
                }
            }
        }    
    }
    
    protected function tearDown()
    {
        //check expected output and fail if
        //missing file on either side, or doesn't match.
        
        //Need to fix on windows before continuing.
        
        $memoryInMb = memory_get_usage()/1e6;
        $str = '***Memory at End: ' . $memoryInMb . " MB***\n";
        print $str;
        
        //@TODO: Need to fix on windows before continuing.
        if ( ButlOsEnum::thisOS() == ButlOSEnum::LINUX() ||  ButlOsEnum::thisOS() == ButlOSEnum::MAC() || ButlOsEnum::thisOS() == ButlOSEnum::WINDOWS() )
        {              
            $filesExp =  $this->getAllInDir( $this->getExpectedD() );
            $filesNew =  $this->getAllInDir(    $this->getOutputD() );
            
            $compareFiles = $this->compareDir ($filesExp, $filesNew );
            
            
            $isPassed = true;
            
            if ( count($filesExp) -> 0 )
            {
                print "+++Error: Files were missing from output+++\n";
                print_r ( array_values($filesExp) );
                $isPassed = FALSE;
            }
            if ( count($filesNew) -> 0 )
            {
                print "+++Error: Extra Files found in output+++\n";
                print_r ( array_values($filesNew) );
                $isPassed = false;
            }
            
            
            $notMatchedArray = array();
            foreach ($compareFiles as $fileCompare )
            {
                $osCommands = new ButlOsCommands();
                $outputPath = $osCommands->joinPath($this->getOutputD() , $fileCompare);
                $expectedPath = $osCommands->joinPath($this->getExpectedD(), $fileCompare);
                
                $rv = $this->compareFiles( $outputPath , $expectedPath);
                if (!$rv)
                {
                    array_push($notMatchedArray,  $fileCompare);
                }
                else
                {
                    print "+++Success: $fileCompare +++\n";
                }
            }
            if ( count($notMatchedArray) -> 0 )
            {
                print "+++Error: Files Contents Not Matched +++\n";
                print_r ( array_values($notMatchedArray) );
                $isPassed = false;
            }
            if (!$isPassed)
            {
                print  "To Compare: " . PHP_EOL . "WinmergeU " . $this->getExpectedD() . " " . $this->getOutputD() . PHP_EOL;            
            }
            $this->assertTrue($isPassed, "The Test Results Data did not match expected");
        }    
    }
    
    
    /**
    * This Function compares files into two directory and returns the files that
    * are the same.  It also returns the input parameters with files that only exist in those directory
    * The caller can use this for further decisions.
    * The assumption is the directory list is sorted.
    * @array $expectedlist
    * @array $newList
    * @array $comparables
    */
    public function compareDir(&$expectedlist, &$newList)
    {
        //if sorted just go down linearly.
        $comparables = array();
        $count1 = count($expectedlist);
        $count2 = count($newList);
        
        
        
        if ($count1 <= 0 || $count2 <= 0 )
        {
            return array();
        }
        
        $i = 0;
        $j = 0;
        do
        {
            $cmp = strcmp( $expectedlist[$i], $newList[$j] );
            if ( $cmp != 0  )
            {
            if ( $cmp -> 0)
            {
                $i++;
            }
            else
            {
                $j++;
            }
            
            }
            else
            {
                array_push($comparables, $expectedlist[$i]);
                array_splice($expectedlist, $i, 1);
                array_splice($newList, $j, 1);
            }
            
        } while ($i < count($expectedlist) && $j < count($newList) );
        
        return $comparables;
        }
        
        public function compareFiles($file1, $file2)
        {
            $isMatch = FALSE;
            $contents1 = file($file1, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES   );
            $contents2 = file($file2, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES   );
            $t1 = array_diff($contents1, $contents2) ;
            $t2 = array_diff($contents2, $contents1) ;
            if (  count ( $t1 )  == 0 &&  count ( $t2 ) == 0)
            {
            $isMatch = TRUE;
        }
        return $isMatch;
    }
    
    /*
    * @string $path
    * @array $dir
    */
    public function getAllInDir($path)
    {
        $dir = array();
        
        if ( is_dir($path) )
        {
            $directory = dir($path);
            
            if (!$directory) return array();
            
            while ( false !== ($entry = $directory->read()) )
            {
                $osCommands = new ButlOsCommands();
                $filePath = $osCommands->joinPath($path , $entry);           
                if( is_file($filePath))
                {
                    array_push( $dir, $entry);
                }
            }
        }
        return $dir;
    }
    
    
    public function readInput($file, $mode)
    {
        $osCommands = new ButlOsCommands();
        $filePath = $osCommands->joinPath($this->getInputD() , $file);       
        $output = file_get_contents ( $filePath );
        return $output;    
    }
    
    public function writeOutput($file, $output)
    {
        $osCommands = new ButlOsCommands();
        $filePath = $osCommands->joinPath( $this->getOutputD() , $file);            
        file_put_contents( $filePath,  $output);
        return TRUE;
    
    }
    
}
2) Now create a Test Listener which allows us to format different types of failures..
 

class Btst_SimpleTestListener extends PHPUnit_TextUI_ResultPrinter
{
    
    /**
    * @var integer
    */
  protected $_numAssertions = 0;
  
  public function addError(PHPUnit_Framework_Test $test,
           Exception $e,
           $time)
  {
    printf(
      "Error while running test '%s'.\n",
      $test->getName()
    );
  }
 
  public function addFailure(PHPUnit_Framework_Test $test,
             PHPUnit_Framework_AssertionFailedError $e,
             $time)
  {
    printf(
      "Test '%s' failed.\n",
      $test->getName()
    );
  }
 
  public function addIncompleteTest(PHPUnit_Framework_Test $test,
                    Exception $e,
                    $time)
  {
    printf(
      "Test '%s' is incomplete.\n",
      $test->getName()
    );
  }
 
  public function addSkippedTest(PHPUnit_Framework_Test $test,
                 Exception $e,
                 $time)
  {
    printf(
      "Test '%s' has been skipped.\n",
      $test->getName()
    );
  }
 
  public function startTest(PHPUnit_Framework_Test $test)
  {
   $name = $test->getName();
    $nowDate = new ButlDateTimeUtils();
    $nowDateStr = $nowDate->retrieveUTCFormat();
    $buffer = sprintf(
      "\n------------------------------------------------" .
      "\n---------------Starting: '%s'  Date: '%s'" .
      "\n------------------------------------------------\n",
      $name, $nowDateStr
    );
    print ($buffer);

        
  }
     /**
     * @param  PHPUnit_Framework_Test $test
      * @param float $time
     */
  public function endTest(PHPUnit_Framework_Test $test, $time)
  {
   
    $result = $test->getResult();
    $this->writeGlobalProgress($test);

    $nowDate = new ButlDateTimeUtils();
    $nowDateStr = $nowDate->retrieveUTCFormat();

    
    //$success = $result->wasSuccessful();
    $msg = $test->getStatusMessage();
    $success = $test->hasFailed() == TRUE ? "FAIL":"SUCCESS";
 
    
    printf(
        "\n-->Date:  $nowDateStr " .
        "\n-->Duration:  $time " .
       "\n-->FINISHED with result: $success($msg)"
    );
  }
 
  public function startTestSuite(PHPUnit_Framework_TestSuite $suite)
  {
    printf(
"\n****************************************************************************" .
"\n****************TestSuite '%s' started" .
"\n****************************************************************************\n" ,
      $suite->getName()
    );
    
    
  }
 
  public function endTestSuite(PHPUnit_Framework_TestSuite $suite)
  {
  
   if ($suite instanceOf BTST_Formatted_TestSuite)
   {
    $results = $suite->_getSuiteResult();
    $results = $results;
    $resultStr = $results->wasSuccessful() == TRUE ? "SUCCESSFULL":"FAILED";
 printf(
 "\n****************************************************************************".
 "\n**************** TestSuite " . $suite->getName() . " " . $resultStr .
 "\n****************" .
 "\n**************** Total Cases: ". $results->count()  .
 "\n**************** Total Passes: ". ($results->count() - $results->failureCount()).
 "\n**************** Total Failed: ". $results->failureCount() .
 "\n**************** Total Errors: ". count($results->errors()) .
 "\n**************** Total Assertions: ". $this->_numAssertions .
 "\n**************** Total Time: ". $results->time() . " s" .
 "\n****************************************************************************\n");
     
        $this->printFailures($results);
        $this->printErrors($results);
   }
    
    else
    {
     printf("\n**************** TestSuite " . $suite->getName() . " Finished");
    }
    
    //Results
    
    
  }
  
  
   /**
     *
     */
    public function writeGlobalProgress($testCase)
    {
     $this->_numAssertions += $testCase->getNumAssertions();
    }
}

3) The TestSuite is required to attach a listener to the TestResult that we defined above.  We can setup other things like how errors are shown and strict mode testing
 
class Btst_Formatted_TestSuite extends PHPUnit_Framework_TestSuite
{
 
 /*
 * This override the createResult to include our customer listner
 *
 */
 
 protected $_suiteResult = NULL; //hold the result so we can use it later
 
 public function createResultForListner()
 {

  $this->_suiteResult = new PHPUnit_Framework_TestResult;
  $this->_suiteResult->strictMode(TRUE);
  $this->_suiteResult->convertErrorsToExceptions(TRUE);
  $this->_suiteResult->addListener(new Btst_SimpleTestListener);
  return $this->_suiteResult;
 }
 
 public function _getSuiteResult()
 {
  return $this->_suiteResult;
 }
    
    /*
    * For some reason our createResult does not get called, so I had to override run.
    *
    */
    public function run(PHPUnit_Framework_TestResult $result = NULL, $filter = FALSE, array $groups = array(), array $excludeGroups = array(), $processIsolation = FALSE)
    {
        $result = $this->createResultForListner();
        PHPUnit_Framework_TestSuite::run($result, $filter, $groups, $excludeGroups, $processIsolation);
    }
    
    protected function setUp()
    {
    print "\nBTST_Formatted_TestSuite::setUp()";
    print "\n+++++++++++++++++++++++++++++++++";
    
    }
    
    protected function tearDown()
    {
    print "\n+++++++++++++++++++++++++++++++++";
    print "\nBTST_Formatted_TestSuite::tearDown()";
    }
    
}
4) Finally here's a typical test case.  There is not much change except we can save outputs and let the rest do its magic.  You can also run the without the special formatting if you want to revert back to phpunit default settings.
 
/*
* Test Driver for the ArrayTest test suite
*  phpunit --verbose  BCOM_SegmentFormat_AllTests BcomSegmentFormatTest.php
* The following line will run without the all the extensions.
*  phpunit --verbose  BcomSegmentFormatTest.php
*  
*/

class BCOM_SegmentFormat_AllTests
{
    public static function suite()
    {
        $suite = new Btst_Formatted_TestSuite('BcomSegmentFormatTest');
        return $suite;
    }
    
    public static function suiteRollUp()
    {
        $suite = new PHPUnit_Framework_TestSuite('BcomSegmentFormatTest');
        return $suite;
    }
}
    
    
class BcomSegmentFormatTest extends Btst_Framework_TestCase
{
    //*************INSERT THESE THREE FUNCTIONS IN ALL TEST CASES*************************//
    static function setUpBeforeClass()
    {
        Btst_Framework_TestCase::setUpBeforeClassClearOutDir( realpath(dirname(__FILE__) ) );
        
        //Need to do special on windows!!!
        Btst_Framework_TestCase::loadDatabase_Helper(true, "password", "default");
    }
    
    
    protected function setUp()
    {
    
        _fullUnitPath = realpath(dirname(__FILE__) );
        Btst_Framework_TestCase::setUp();
    }
    //**********************************************************************************//

    protected function tearDown()
    {
        Btst_Framework_TestCase::tearDown();
        //do gnokii tear down
    }

public function test10_testLocalIncomingDropbox()
    {
         
        $allInputs = $this->getAllInDir ( $this->getInputD() );
        $file = doStuff($allInputs);
        copy( $file, $this->getOutputD() );

}


So there you go.  The output at the end now outputs more information about the failures so you don't have to go trolling through the log.  Also the formatting breaks of +++ and **** allow for better visual clues about which output is associated with a given test, and allow for further processing as needed.   So thats about it.  If you want to also run an entire test suite from a top level acceptance, the following snippet can be used.


 
/*
* Runs all tests in our acceptance suite.
* Create a test suite that contains the tests
* from the ArrayTest class.
* Just in one of the following ways.
*  phpunit --verbose AcceptanceTestSuite.php
*  phpunit --filter test2_pop AcceptanceTestSuite.php
*/
class AcceptanceTestSuite
{

public static function suite()
{
    $suite = new Btst_Formatted_TestSuite('Executing ... Your Test Suite');
    $suite->addTest(BCOM_SegmentFormat_AllTests::suiteRollUp());
    $suite->addTest(BBBB_Business_AllTests::suiteRollUp());
    return $suite;
}
}

Sunday, January 22, 2012

Tech : Singleton MDB on Glassfish 3 on OpenMq

With EJB 3.1 specification it is possible to specify MDB (message driven beans) that can be included in a glassfish web profile and packaged into .WAR file.  This enables pooling out of the box with minimal configuration.

With all these new changes, sometimes it gets quite confusing for IDE like Netbeans to keep up.  In my experience configuring JMS on Netbeans was bit of chore once you start customizing.   I needed to connect to a public REST interface with a rate limit, so I actually only wanted one JMS message at time to be processed, which was more work then I thought.

Its key to note the pool size of the CONSUMER and CONNECTION are not what makes the JMS consumer concurrent, instead its the MDB bean pooling.  This is important to note before you start changing your <connector-connection-pool> with max-pool-size="1" steady-pool-size="1".  Doing so will only change the max connections allowed, which is not what you want typically and cause timeouts as soon as more than one client connects.  Also imqConnectionFlowLimit="50"  imqConsumerFlowLimit = "1000", only change how we batch messages from the queue broker to the consumer.  It again does not impact concurrency.

Finally using synchronized keyword has no impact on a MDB.  It is because the MDB is design to run on clusters, which would not make is possible to synchronize across a cluster.  You should never try to manage threading when using any bean, including an MDB.

Below are steps to configure simple MDB with Queue Connection.  I'm use CMT (container managed transactions) and also ObjectMessage DTO to serialize the message.  A thread sleep is put into to achieve quick and dirty rate buferring.

1) You need to add your queue broker via jar files, imq.jar and jms.jar to your project http://mq.java.net/.

2) Add Connector resources for the jms/javaee6/FranchiseLocationQueue in glassfish-resources.xml (note old name sun-resources.xml)
 

        
            
            
    
    
3) Create a message driven consumer.  Note the transaction are managed by the container and connection by the persistence unit.  Transaction is started automatically before OnMessage();
 
@MessageDriven(mappedName = MMSG_FranchiseLocationConsumer.QUEUE_NAME,  description="Geoencodes Franchises", activationConfig = {
        @ActivationConfigProperty(  propertyName = "destinationType", propertyValue = "javax.jms.Queue"),                                                                                  
        @ActivationConfigProperty(  propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),  
} )
public class MMSG_FranchiseLocationConsumer implements MessageListener 
{
    
    public final static String CONN_FACTORY_NAME = "jms/javaee6/FranchiseLocationFactory";    
    public final static String QUEUE_NAME = "jms/javaee6/FranchiseLocationQueue"; 

    @PersistenceContext(unitName = "myPU")
    private EntityManager _em;
       
    //This is the context of this bean.
    @Resource
    private MessageDrivenContext context;      
    
    private static Log log = LogFactory.getLog(MMSG_FranchiseLocationConsumer.class);   
    
    // Constructor. Establish JMS publisher and subscriber 
    public MMSG_FranchiseLocationConsumer() throws Exception 
    {        
            log.info("Starting JMS Queue" + QUEUE_NAME);
    }
        
    // Receive message from topic subscriber  
    
    /*
     * The default is for the container to start a transaction before the onMessage method is invoked and will commit the transaction when the method returns, 
     * unless the transaction was marked as rollback through the message-driven context. There is more about transactions to discuss but for our discussion of MDBs, 
     * this will suffice. 
     */
    //
    @Override
    public void onMessage(Message message) {

        String msgId = "";
        MMSG_FranchiseDTO franchiseDTO = null;
        try 
        {
            ObjectMessage objectMessage = (ObjectMessage) message;
            
            msgId = objectMessage.getJMSMessageID();
            franchiseDTO = (MMSG_FranchiseDTO) objectMessage.getObject();
            
            log.info("Recieved Msg with Id:" + msgId + "with city:" + franchiseDTO.getFr().getAddress1() );           
        } 
        catch (JMSException e)
        { 
            log.debug("Failed to process message: " + msgId + " with exception" + e);
            context.setRollback(); return;
        }         
        addFranchiseToDb( franchiseDTO.getFr(), franchiseDTO.getBusinessGroupId() );
    }
    
    private void addFranchiseToDb(FranchisesRaw fr, int businessGroupId)
    {
        try
        {
            Thread.sleep(1); //note we could be prudent and keep the last accessed time and put a timer on it.
        }
        catch (InterruptedException e)
        {
            log.error("Interrupted Exception" + e);
        }                
        //Call your rate limited API here
    }         
}

4)  Add producer code in function as you'd like
Context ctx = null;           
ctx = new InitialContext();
_connFactory = (ConnectionFactory) ctx.lookup(MMSG_FranchiseLocationConsumer.CONN_FACTORY_NAME);
_franchiseQueue = (Queue) ctx.lookup(MMSG_FranchiseLocationConsumer.QUEUE_NAME);
initConnection();            
Session session = _connection.createSession(true, Session.AUTO_ACKNOWLEDGE);
MessageProducer producer = session.createProducer(_franchiseQueue);
ObjectMessage message = session.createObjectMessage();
message.setJMSMessageID("test message 1");
message.setObject( new MMSG_FranchiseDTO( franchiseRaw, businessGroupId ) );
producer.send(message);
session.close();
_connection.close();

5) Add the DTO object that we can pass across as a message (note you can bundle other POJO's like Database Entity files across.
        
public class MMSG_FranchiseDTO implements Serializable
{
   int _businessGroupId;
    FranchisesRaw _fr;
}

6) Now if you want a singleton bean, the following needs to be added manually to the web/WEB-INF folder in glassfish-ejb-jar.xml  By default Netbeans will copy everything in WEB-INF, so you don't need to worry about adding to build-impl.xml.  Also if you ask Netbean to add a"standard-deployment-descriptor" it will only add a ejb-jar.xml, which DOES NOT have all the options you get from the glassfish deployment descriptor.

  
  First Module
  
    
      MMSG_FranchiseLocationConsumer
      jms/javaee6/FranchiseLocationQueue
      
        1
        1
        1
        600
      
    
    
      singleton-bean-pool
      true
    
  


And there you go.  You can manipulate the pool size and make the MDB singleton or not as you wish. The JMS by default will run on the same JVM in "embedded" mode, which in my case was exactly what I needed.