Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Examples  

examp18.cpp

This example is to show use of the Command pattern. There are three(3) self documenting tests that are run:

1. Create a command which converts a mixed case string to upper case. 2. Same as #1 but add a reverse command and intentionaly undo the change. 3. Add the command and reverse and a little nasty suprise to force the CommandFrame to roll-back the commands automatically because of a problem in the transaction.

/*
  CoreLinux++ 
  Copyright (C) 2000 CoreLinux Consortium
  
   The CoreLinux++ Library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public License as
   published by the Free Software Foundation; either version 2 of the
   License, or (at your option) any later version.

   The CoreLinux++ Library Library is distributed in the hope that it will 
   be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public
   License along with the GNU C Library; see the file COPYING.LIB.  If not,
   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.  
*/   

#include <corelinux/Common.hpp>

#if   !defined(__COMMANDFRAME__HPP)
#include <corelinux/CommandFrame.hpp>
#endif

#include <UpperCaseCommand.hpp>
#include <RestoreCaseCommand.hpp>

using namespace corelinux;

#include <iostream>
#include <exception>

//
// In module function prototypes
//

int   main( void );

//
// General Functions 
//

void  doTestOne( void );
void  doTestTwo( void );
void  doTestThree( void );

void  handleAssertion( AssertionCref );
void  handleException( ExceptionCref );

//
// Global data
//

//
// Main entry point
//


int main( void )
{

   cout << endl;

   //
   // Practice graceful exception management
   //


   try
   {
      //
      // Run the various tests
      //

      doTestOne();
      doTestTwo();
      doTestThree();

   }

   catch( CommandFrameException aException )
   {
      cerr  << "Received CommandFrameException!" << endl;
      handleException(aException);
   }
   catch( AssertionRef aAssert )
   {
      handleAssertion(aAssert);
   }
   catch( ExceptionRef aException )
   {
      handleException(aException);
   }
   catch( std::exception & e )
   {
      cerr  << e.what() << endl;
   }
   catch( ... )
   {
      cerr  << "Unknown exception." << endl;
   }

   return 0;               
}

//
// Some utility functions
//

CommandFramePtr   createTransaction( bool autoMode = true );
void              destroyTransaction( CommandFramePtr );
void              displayResults( CommandFramePtr );
CommandPtr        createUpperCommand( void );
void              cleanupCommands( CommandFramePtr );

// Test One Simple

void  doTestOne( void )
{
   cout << endl;
   cout << "With the first test we create a command that " << endl;
   cout << "converts a string to upper case." << endl;
   cout << endl;

   CommandFramePtr   aTransaction(NULLPTR);

   try
   {
      aTransaction = createTransaction( false );
      aTransaction->addCommand( createUpperCommand() );
      aTransaction->execute();
      displayResults( aTransaction );
      destroyTransaction( aTransaction );
   }
   catch( ExceptionRef aExcp )
   {
      if( aTransaction != NULLPTR )
      {
         destroyTransaction( aTransaction );
      }
      else
      {
         ;  // do nothing
      }
      throw;
   }


}

CommandPtr        createUpperAndReverseCommand( void );

// Test two (imagine a undo stack!!!

void  doTestTwo( void )
{
   cout << endl;
   cout << "With the next test we create a command that " << endl;
   cout << "converts a string to upper case. We also add " << endl;
   cout << "an undo command, we execute and then undo the " << endl;
   cout << "change displaying as we go. THINK UNDO STACK!!! " << endl;
   cout << endl;

   CommandFramePtr   aTransaction(NULLPTR);

   try
   {
      aTransaction = createTransaction( true );
      aTransaction->addCommand( createUpperAndReverseCommand() );
      aTransaction->execute();
      displayResults( aTransaction );
      aTransaction->executeReverse();
      displayResults( aTransaction );
      destroyTransaction( aTransaction );
   }
   catch( ExceptionRef aExcp )
   {
      if( aTransaction != NULLPTR )
      {
         destroyTransaction( aTransaction );
      }
      else
      {
         ;  // do nothing
      }
      throw;
   }
}

// Bogus run on purpose!

//
// The nasty ugly that excercises the CommandFrame
// rollback
//

class UglyCommand : public Command
{
public:
               UglyCommand( void )
                  :
                  Command()
               {
                  ;  // do nothing
               }

   virtual     ~UglyCommand( void )
   {
      ;  // do nothing
   }
   virtual void execute( void )
   {
      throw Exception("Candy gram for Mungo",LOCATION);
   }
};

void  doTestThree( void )
{
   cout << endl;
   cout << "In this test, we put a nasty little command that " << endl;
   cout << "forces the CommandFrame to rollback itself AFTER " << endl;
   cout << "the UpperCaseCommand. The resulting output should " << endl;
   cout << "show that the original string is restored." << endl;
   cout << endl;

   CommandFramePtr   aTransaction(NULLPTR);

   try
   {
      aTransaction = createTransaction( true );
      aTransaction->addCommand( createUpperAndReverseCommand() );
      aTransaction->addCommand( new UglyCommand );
      aTransaction->execute();
      displayResults( aTransaction );
      destroyTransaction( aTransaction );
   }
   catch( ExceptionRef aExcp )
   {
      if( aTransaction != NULLPTR )
      {
         destroyTransaction( aTransaction );
      }
      else
      {
         ;  // do nothing
      }
      throw;
   }
}

//
// Allocate a CommandFrame
//

CommandFramePtr   createTransaction( bool autoMode )
{
   return new CommandFrame( autoMode );
}

//
// Destroy the command frame
//

void destroyTransaction( CommandFramePtr aTransaction )
{
   cleanupCommands( aTransaction );
   delete aTransaction;
}

//
// Iterate the results
//

void displayResults( CommandFramePtr aTransaction )
{
   REQUIRE( aTransaction != NULLPTR );

   Commands    aCollection;
   WorkState   aRunFlag( aTransaction->getState() );
   
   cout << "Transaction state = " <<
      ( aRunFlag == COMPLETED ? "Success" :
         ( aRunFlag == REVERSED ? "Rolled back" : "Invalid" ) ) << endl;
            

   aTransaction->getCommands(aCollection);

   CommandsIterator  begin( aCollection.begin() );

   while( begin != aCollection.end() )
   {
      if( dynamic_cast<UpperCaseCommandPtr>((*begin)) != NULLPTR )
      {
         cout << "Upper case results = " << 
            dynamic_cast<UpperCaseCommandPtr>((*begin))->getNewValue() << endl;
      }
      ++begin;
   }

   cout << endl;
   
}

//
// Create the to UpperCase command
//

CommandPtr  createUpperCommand( void )
{
   string   aString;

   cout  << "Enter a mixed case string : ";
   cin >> aString;

   return new UpperCaseCommand( aString );
}

//
// Create the Upper command and the ability
// to restore it.
//

CommandPtr  createUpperAndReverseCommand( void )
{
   CommandPtr  baseCmd( createUpperCommand() );
   CHECK( baseCmd != NULLPTR );

   CommandPtr  undoCmd( new RestoreCaseCommand );
   CHECK( undoCmd != NULLPTR );

   baseCmd->setReverseCommand( undoCmd );

   return baseCmd;
}
//
// Iterates through the transaction and deletes
// the commands and reverse commands
//

void  cleanupCommands( CommandFramePtr aTransaction )
{
   REQUIRE( aTransaction != NULLPTR );

   Commands aCollection;
   
   aTransaction->getCommands(aCollection);

   CommandsIterator  begin( aCollection.begin() );

   while( begin != aCollection.end() )
   {
      CommandPtr  aCmdPtr( static_cast<CommandPtr>(*begin) );
      if( aCmdPtr->getReverseCommand() != NULLPTR )
      {
         delete aCmdPtr->getReverseCommand();
         aCmdPtr->setReverseCommand( NULLPTR );
      }
      else
      {
         ;  // do nothing
      }

      delete aCmdPtr;
      ++begin;
   }
}

//
// Error handlers
//

void  handleAssertion( AssertionCref aAssert )
{
   cerr << aAssert.getFile() << ":" << aAssert.getLine() << ":" << 
      "Assertion: ";

   if( aAssert.getType() == Assertion::NEVERGETHERE )
   {
      cerr << "NEVER_GET_HERE";
   }
   else
   {
      if( aAssert.getType() == Assertion::REQUIRE )
      {
         cerr  << "REQUIRE";
      }
      else if( aAssert.getType() == Assertion::ENSURE )
      {
         cerr  << "ENSURE";
      }
      else if( aAssert.getType() == Assertion::CHECK )
      {
         cerr  << "CHECK";
      }
      else 
      {
         cerr  << "ASSERT";
      }
      cerr << "( " << aAssert.getWhy() << " )";
   }

   cerr << endl;
}

void  handleException( ExceptionCref aExcp )
{
   cerr << aExcp.getFile() << ":" << aExcp.getLine() << ":" <<
      "Exception: " << aExcp.getWhy() << endl;
}

/*
   Common rcs information do not modify
   $Author: prudhomm $
   $Revision: 1.2 $
   $Date: 2000/08/31 22:49:02 $
   $Locker:  $
*/



This is the CoreLinux++ reference manual
Provided by The CoreLinux Consortium