How to use Exceptions / Conditions

Exceptions are used to illustrate errors and problems in the code. Examples are illegal states of the hardware or out of range occurences. The term condition is used to not only illustrate errors and problems but also positive states.

First of all: the general Description

Exception texts and their descriptions as well as their translations and severity levels are described in an XML file. The facility ID is usually a 4-digit number below 1000 . The number can be obtained by the database maintainers.

Example:

<?xml version="1.0" encoding="UTF-8"?>
<facilityConditions  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://websvcdev.acc.gsi.de/groups/cscosv/condition-utils/facility.xsd">
  <facilityName>FESATEST</facilityName>
  <facilitySymbol>FESATEST</facilitySymbol>
  <facilityId>TODO please obtain the facility ID by the database maintainers TODO</facilityId>
     <severities>
       <severity level="SUCCESS">
         <condition name="OK">
            <text>
               <de>Normal successful completion</de>
               <en>Normal successful completion</en>
            </text>
            <description>
               <de>none</de>
               <en>none</en>
            </description>
         </condition>
       </severity>
       <severity level="ERROR">
         <condition name="UNKNOWN_ERROR">
            <text>
               <de>Fehler unbekannt</de>
               <en>Error unknown</en>
            </text>
            <description>
               <de>Unbekannter Fehler</de>
               <en>Unknown error</en>
            </description>
         </condition>
         <condition name="OUT_OF_RANGE">
            <text>
               <de>Ausserhalb des Bereichs</de>
               <en>Out of range</en>
            </text>
            <description>
               <de>none</de>
               <en>none</en>
            </description>
         </condition>
         <condition name="ILLEGAL_OPERATION">
            <text>
               <de>Nicht zulaessige Operation</de>
               <en>Illegal operation</en>
            </text>
            <description>
               <de>none</de>
               <en>none</en>
            </description>
      </condition>
    </severity>
</facilityConditions>

Database Handling

The content of this XML file is loaded into the database:

conditions-loader insert -file FESATEST.xml

A C++ header file is extracted from the database using the command

conditions-loader get -all -facilities
conditions-generator -H

This header (in ./compiled/cheader/) contains error codes that should be used within a FESA class.

Existing conditions for each equipment software can be displayed with
conditions-loader list
conditions-loader list -sortbyname

A single condition.xml file can be extracted from the database with
conditions-loader get -facilities <NAME> -path .

FESA Eclipse Plug-In Integration

From FESA3 3.1.0 on the FESA Eclipse Plug-In 2.5.5 provides a button (conditions.png) to handle the condition tools. The button is located on the FESA class design toolbar.
  • First the database will be checked wether conditions for the FESA class already exist.
    • If they exist the conditions will be downloaded from the database.
    • If they don't exist yet a template for the conditions will be generated in the workspace.
  • The generated/downloaded template in XML format should be adapted for the specific FESA class.
  • Please refer to Udo Krause / Ludwig Hechler (CSCOFE) for the proper facilityId.
  • If the file is ready for insertion the button (conditions.png) can be used for uploading the conditions into the database.
  • If the conditions for this FESA class already exist in the database the database will be updated instead.
  • In the end the conditions header will be generated in FESACLASS/src/FESACLASS/Common .

FESA Source Code

Conditions without parameters

Condition Description Example

...
<text>
    <de>Da lief was schief<de>
    <en>Something went wrong<en>
</text>
...

Place the generated header in src/<class name>/Common/UserCode . In case of an error or problem throw an exception, e.g. like this:

throw fesa::FesaException("additional message",__FILE__, __LINE__, FESA_TEST_UNKNOWN_ERROR, "theCategory");

From FESA3 3.1.0 on a condition should be thrown using the GSI specific macro:
// throw value of generated condition header in FESACLASS/src/FESACLASS/Common
#include <FESACLASS/src/FESACLASS/Common/FESACLASSmsg.h>
throw CONDITION(__FILE__, __LINE__, FESACLASS_CONDITION_X, "a user defined message");

The result is something like

Caused by:
cern.cmw.rda3.common.exception.ServerException:   CONDITION:187727882:0xb30800a GSITEMPLATE-E-UNKNOWN_ERROR:execute. src/GSITemplate/Server/ThrowConditionSetAction.cpp:59
  at cern.cmw.rda3.common.util.ExceptionUtils.createRdaServerException(ExceptionUtils.java:75)
  at cern.cmw.rda3.impl.common.request.RequestSerializerImpl.deserializeException(RequestSerializerImpl.java:272)
  at cern.cmw.rda3.impl.common.request.RequestSerializerImpl.deserializeBody(RequestSerializerImpl.java:382)
...

Conditions with Parameters

Condition Description Example

...
<text>
<de>Wert {0} ausserhalb des Bereichs (Min: {1}.. max:{2})</de>
<en>Setting {0} out of range (Min: {1}.. max:{2})</en>
</text>
...

Implementation

See Conditions without parameters. Instead of using the condition macro the constructor for throwing a GSIException can be used to throw a condition with parameters.

Example:

throw fesaGSI::GSIException(GSITEMPLATE_ILLEGAL_OPERATION, #GSITEMPLATE_ILLEGAL_OPERATION", "AParameter;BParameter;CParameter");

The result is something like

...
Caused by:
cern.cmw.rda3.common.exception.ServerException: CONDITION: 187727882:0x4d2 GSITEMPLATE-E-ILLEGAL_OPERATION/pAParameter  . :-1
  at cern.cmw.rda3.common.util.ExceptionUtils.createRdaServerException(ExceptionUtils.java:75)
...

Helpers like these can be used:

#define FORM_CONDITION(code) fesaGSI::GSIException::FORMAT_CONDITION(CONDITION_NAME(#code), code)

inline fesaGSI::GSIException createException(const std::string &file,
      const int32_t &lineNumber, std::string code, CMW::Log::Logger &logger) {
   std::ostringstream msg;
   msg << file << "::" << lineNumber << ": #@#" << code << "#@#";  // IMPORTANT: #@# is the new delimiter from 2022 on to allow easy condition parsing for applications
   LOG_ERROR_IF(logger, msg.str());

   return fesaGSI::GSIException(file, lineNumber, code.c_str());
}

inline fesaGSI::GSIException createException(const std::string &file,
        const int32_t &lineNumber, std::string code, const std::string nomen,
        CMW::Log::Logger &logger) {
    std::ostringstream msg;
    std::ostringstream exceptMsg;
    exceptMsg << ": device " << nomen << ": #@#" << code << "#@#";  // IMPORTANT: #@# is the new delimiter from 2022 on to allow easy condition parsing for applications

    msg << file << "::" << lineNumber << exceptMsg.str();
    LOG_ERROR_IF(logger, msg.str());

    return fesaGSI::GSIException(file, lineNumber, exceptMsg.str().c_str());
}

inline fesaGSI::GSIException createException(const std::string &file,
        const int32_t &lineNumber, std::string code, std::string message,
        std::string nomen, CMW::Log::Logger &logger) {
    std::ostringstream msg;
    std::ostringstream exceptMsg;
    exceptMsg << ": device " << nomen << ": #@#" << code << "#@#:" << message;  // IMPORTANT: #@# is the new delimiter from 2022 on to allow easy condition parsing for applications

    msg << file << "::" << lineNumber << exceptMsg.str();
    LOG_ERROR_IF(logger, msg.str());

    return fesaGSI::GSIException(file, lineNumber, exceptMsg.str().c_str());
}

inline fesaGSI::GSIException createRangedException(const std::string &file,
        const int32_t &lineNumber, std::string code, double val, double min,
        double max, std::string nomen, CMW::Log::Logger &logger) {
    std::ostringstream msg;
    std::ostringstream exceptMsg;
    exceptMsg << ": device " << nomen << ": #@#" << code << "#@# Value " << val
            << " out of range [" << min << "," << max << "]";  // IMPORTANT: #@# is the new delimiter from 2022 on to allow easy condition parsing for applications

    msg << file << "::" << lineNumber << exceptMsg.str();
    LOG_ERROR_IF(logger, msg.str());

    return fesaGSI::GSIException(file, lineNumber, exceptMsg.str().c_str());
}

To provoke a condition:

throw(createException(__FILE__, __LINE__, FORM_CONDITION(MOTORSLIT_UNKNOWN_ERROR), device->getName(), logger));

Results

Caused by: cern.cmw.rda3.common.exception.ServerException: USER_ERROR: Error caused by: : device motor1_tstci26: #@#0xbe7800a "MOTORSLIT-E-UNKNOWN_ERROR"#@#:: device Reference drive not yet performed for motor1: #@#0xbe7801a "MOTORSLIT-E-ILLEGAL_OPERATION"#@#. src/MotorSlit/Common/MBoxDriver.cpp:31. src/MotorSlit/Server/SettingSetAction.cpp:98<br />device="motor1_tstci26" property="Setting" selector="" requestType="SET"

To Consider

References

https://www-acc.gsi.de/wiki/Service/Intern/ConditionCompiler

-- SolveighMatthies - 24 Sep 2015
Topic revision: r14 - 11 Jan 2022, SolveighMatthies
This site is powered by FoswikiCopyright © by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding Foswiki? Send feedback