3D PLM Enterprise Architecture

Middleware Abstraction

Creating and Using Errors

Informing your clients when your program fails
Use Case

Abstract

This article shows how to create, instantiate, retrieve, and decode an error.


What You Will Learn With This Use Case

This use case is intended to show you how to create, instantiate, retrieve, and decode an error.

[Top]

The CAASysError Case

CAASysError is a set of use cases of the CAASystem.edu framework that illustrates the System framework capabilities.

[Top]

What Does CAASysError Do

This use case creates an error class [1] intended to go with a failure returned by methods of the sample class CAASysError. The SquareRoot method computes a square root, and the Subtract method computes a subtraction. The square root makes sense if the number used to compute the square root is greater than or equal to zero, otherwise the method fails. Assume that the subtraction makes sense only if the first operand is greater than or equal to the second, and otherwise the method fails.

[Top]

How to Launch CAASysError

To launch CAASysError, you will need to set up the build time environment, then compile CAASysError along with its prerequisites, set up the run time environment, and then execute the use case [2].

[Top]

Where to Find the CAASysError Code

The CAASysError use case is made of a a class and a main porgram located in the CAASysError.m module of the CAASystem.edu framework:

Windows InstallRootDirectory\CAASystem.edu\CAASysError.m\
Unix InstallRootDirectory/CAASystem.edu/CAASysError.m/

where InstallRootDirectory is the directory where the CAA CD-ROM is installed.

[Top]

Step-by-Step

To create and use an error, there are three main steps:

# Step Where
1 Create an error class CAASysError class
2 Return a failure without using an error class CAASysOperator class
3 Return a failure using an error class and a simple error message CAASysOperator class
4 Return a failure using an error class and a composite error message CAASysOperator class
5 Retrieve and decode an error in a client application CAASysMain.cpp

The CAASysOperator class is used to implement the methods used as examples.

[Top]

Creating an Error Class

A error class derives from CATError, or from one of its derived class, such as CATInputError. The CAASysError class header file is as follows:

...
#include "CATInputError.h"

class CATSysError: public CATInputError
{
  public:
    CATDeclareError(CATSysError, CATIntputError)
};

The CATDeclareError macro declares that the class CAASysError declares an error class that derives from CATInputError. The macro creates the class constructor and method signatures. Let's have a look at the class source file:

#include "CAASysError.h"

CATImplementError(CATSysError, CATInputError);
CATImplementNLSErrorClass(CATSysError);

The CATImplementError macro creates the body of the methods declared by CATDeclareError. The CATImplementNLSErrorClass macro enables the error class for error messages.

[Top]

Returning a Failure Without Using an Error Class

The Divide method divides two real numbers passed as its first two parameters and return the result uinsg the third one.

HRESULT CAASysOperator::Divide(float iDividend, float iDivisor, float * oResult)
{
  if ( 0.0 == iDivisor )
  {
    return(CATReturnFailure);
  } else 
  {
    *oResult = iDividend/iDivisor;
    return(CATReturnSuccess);
  };
}

When the divisor is equal to zero, the result is undetermined. The method simply returns the failure using the CATReturnFailure return code. Otherwise, as long as the method can return a valid result, it returns CATReturnSuccess.

[Top]

Returning a Failure Using an Error Class and a Simple Message

The SquareRoot method computes the square root of the real number passed as its first parameter, and returns the result in its second one. Nevertheless, the first parameter must be greater than or equal to zero, otherwise the square root doesn't exist and an error is returned.

HRESULT CAASysOperator::SquareRoot(float iValue, float * oResult) 
{
  if ( iValue < 0.0 ) 
  {
    CAASysError * pError = new CAASysError("SquareRootERR_1001", "CAASysError");
    CATUnicodeString param;
    param.BuildFromNum(iValue);
  
    int nbparameter = 1;
    pError->SetNLSParameters(nbparameter, &param);
  
    return(CATReturnError(pError));
  }
  else 
  {
    *oResult= CATSqrt(iValue);
    return(CATReturnSuccess);
  }
}

When iValue is less than zero, an instance of the CAASysError class is created, and the message with the SquareRootERR_1001 key in the CAASysError message catalog is associated with it. This message is stored in the error message file as follows:

SquareRootERR_1001 = "Cannot compute the square root of the negative number /p1";

This message includes a parameter /p1 that must be valued at run time to display the invalid negative value for which the square root computation is  requested. This float value is first converted to a CATUnicodeString instance thanks to the BuildFromNum method, and then the SetNLSRequestParams method associates it with the error message. Then the method returns using the macro CATReturnError, taking the error class instance as parameter. The calling client application can use the returned error along with the message to decide what to do. If the square root can be computed, CATReturnSuccess is returned.

[Top]

Returning a Failure Using an Error Class and a Composite Message

The Subtract method and subtracts iSecond  from iFirst and must return a positive or null result, otherwise an error is returned.

HRESULT CAASysOperator::Subtract(float iFirst, float iSecond, float * oResult) 
{
  if ( iSecond <= iFirst ) 
  {
     *oResult = iFirst - iSecond;
     return(CATReturnSuccess);   
  }
  else
  {
    CAASysError * pError = new CAASysError("SubtractERR_1002", "CAASysError");

//  The is no parameter for the Request part of the message
//  pError->SetNLSRequestParams(nbparameter, &param);
  
    int nbparameter = 2;
    CATUnicodeString param1, param2;
    param1.BuildFromNum(iFirst);
    param2.BuildFromNum(iSecond);
    pError->SetNLSDiagnosticParams(nbparameter, &param1, &param2);

    nbparameter = 1;
    CATUnicodeString param3;
    param3.BuildFromNum(iFirst - iSecond);
    pError->SetNLSAdviceParams(nbparameter, &param3);

    return(CATReturnError(pError));
  }
}

If the subtraction can be computed, CATReturnSuccess is returned. When iSecond is greater than iFirst, an instance of the CAASysError class is created, and the message with the SubtractERR_1002 key in the CAASysError message catalog is associated with it. This message is stored in the error message file as follows:

SubtractERR_1002.Request = "Attempt to subtract two numbers using a subtraction operation
where the first number must be greater than or equal to the second one.";
      
SubtractERR_1002.Diagnostic = "The first number /p1 is smaller than the second one /p2.
The subtraction can't be computed";
     
SubtractERR_1002.Advice = "Check the two numbers, or invert them and multiply
the subtraction result by -1. This gives /p1";

This is a composite message made of three parts: a Request part, a Diagnostic part, and an Advice part. It includes three parameters that must be valued at run time to display the two integers to subtract in the diagnostic part, and a result obtained thanks to a by-pass in the Advice part. The three parameters are first converted to CATUnicodeString instances thanks to the BuildFromNum method. Then the SetNLSDiagnosticParams method associates the first two parameters with the Diagnostic part of the error message, and the SetNLSAdviceParams method associates the possible result with the Advice part. Then the method returns using the macro CATReturnError, taking the error class instance as parameter. The calling client application can use the returned error along with the message to decide what to do.

[Top]

Retrieving and Decoding and Error in a Client Application

The CAAOperator class implements the  Subtract method. A call to Subtract should be made as follows, and the program should go on if Subtract returns CATReturnSuccess.

  ...
  CAASysoperator MyOperator;
  float x, y;
  ... // Value x and y
  float PositiveResult = 0;
  HRESULT status = MyOperator.Subtract(x, y, &PositiveResult);
  if (SUCCEEDED(status)) 
    ... OK, go on working
  ...

Otherwise, if a failure is returned, two cases can arise, whether an error class instance is associated with the failure or not.

  ...
  else 
  {
    CATError * pError = CATError::CATGetLastError(status);
    if ( NULL != pError )
    {
      HRESULT hres = pError->GetReturnCode();
        cout <<"  HRESULT   : " <<  hres << endl;
      
      if ( NULL != pError->GetMsgCatalog() )         // Message catalog name: CAASysError
        cout <<"  Catalog   : " <<  pError->GetMsgCatalog() << endl;

      if ( NULL != pError->GetMsgId() )              // Message key: SubstractERR_1002
        cout <<"  Key       : " <<  pError->GetMsgId() << endl;

      if ( NULL != pError->GetId() )                 // Error identifier: 1002      
        cout <<"  GetId     : " <<  pError->GetId() << endl;

      // Retrieves the full message
      CATUnicodeString ErrorMessage      = pError->GetNLSMessage();
      cout <<"  Complete Message   : " << endl << ErrorMessage.ConvertToChar()<<endl<<endl;
        
      // Retrieves the Request message
      CATUnicodeString RequestMessage    = pError->GetNLSRequest();
      cout <<"  Request Message    : " <<  RequestMessage.ConvertToChar() << endl;
        
      // Retrieves the Diagnostic message
      CATUnicodeString DiagnosticMessage = pError->GetNLSDiagnostic();
      cout <<"  Diagnostic Message : " <<  DiagnosticMessage.ConvertToChar() << endl;

        // Retrieves the Advice message
      CATUnicodeString AdviceMessage     = pError->GetNLSAdvice();
      cout <<"  Advice Message     : " <<  AdviceMessage.ConvertToChar() << endl;

      pError->Release();
    }
    else
      cout << "No error class to retrieve"<< endl;
  else
    ... // Subtract OK, go on working
...

First, the possible error class instance is asked to the error manager using the static method GetLastError of the CATError class. If an error class is returned, the returned code can be retrieved thanks to the GetReturnCode method. Then the error is asked for a possible message, for example using the GetMsgCatalog method. If a message catalog is found, then the error message key and identifier can be retrieved, and the full error message itself, parameterized using the parameter values, can be retrieved and used for display, on the console, or better in a dialog box. Since this is a composite message, each part can be individually retrieved, thanks to the methods GetNLSRequest, GetNLSDiagnostic, and GetNLSAdvice. Note that to display a CATUnicodeString instance on the console, the ConvertToChar method must be used. When the error is not any longer needed, it can be released.

For example, assume that the two parameters passed to Subtract are 7 and 10 respectively.

Try to subtract 7 to 10
  HRESULT   : -2147467259
  Catalog   : CAASysError
  Key       : SubtractERR_1002
  GetId     : 1001
  Complete Message   :
Substract 2 parameters,
but the first parameter must be greater than the second parameter,
so the result is positive
The first parameter, 7, is smaller than the second, 10
Inverse the 2 parameters and multiply the result by -1: that gives -3

  Request Message    : Substract 2 parameters,
but the first parameter must be greater than the second parameter,
so the result is positive
  Diagnostic Message : The first parameter, 7, is smaller than the second, 10
  Advice Message     : Inverse the 2 parameters and multiply the result by -1: that gives -3

[Top]


In Short

This use case shows how to create how to create, instantiate, retrieve, and decode an error.

[Top]


References

[1] Managing Errors
[2] Building and Launching a CAA V5 Use Case
[Top]

History

Version: 1 [Mar 2000] Document created
[Top]

Copyright © 2000, Dassault Systèmes. All rights reserved.