382 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			382 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| Function Error_Services(@Service, @Params)
 | |
| /***********************************************************************************************************************
 | |
| 
 | |
|     This program is proprietary and is not to be used by or disclosed to others, nor is it to be copied without written
 | |
|     permission from SRP Computer Solutions, Inc.
 | |
| 
 | |
|     Name        :   Error_Services
 | |
| 
 | |
|     Description :   Handler program for all error services.
 | |
| 
 | |
|     Notes       :   Application errors should be logged using the Error Services module. There are a few methodological
 | |
|                     assumptions built into way errors are managed which are important to understand in order to properly
 | |
|                     work with Error Services:
 | |
| 
 | |
|                     - The term 'top' refers to the originating procedure of a call stack and the term 'bottom' refers to
 | |
|                       the last routine (or the current routine) within a call stack. Within the OpenInsight Debugger
 | |
|                       this will appear backwards since the originating procedure always appears at the bottom of the
 | |
|                       list and the current routine appears at the top of the list. We are using this orientation because
 | |
|                       it is common to refer to the process of calling other procedures as 'drilling down'.
 | |
| 
 | |
|                     - The reason for defining the orientation of the call stack is because Error_Services allows for
 | |
|                       multiple error conditions to be appended to an original error. In most cases this will happen when
 | |
|                       a procedure at the bottom of the stack generates an error condition and then returns to its
 | |
|                       calling procedure. This higher level procedure can optionally add more information relevant to
 | |
|                       itself. This continues as the call stack 'bubbles' its way back to the top to where the
 | |
|                       originating procedure is waiting.
 | |
| 
 | |
|                     - Native OpenInsight commands that handle errors (e.g., Set_Status, Set_FSError, Set_EventStatus)
 | |
|                       preserve their error state until explicitly cleared. This can hinder the normal execution of code
 | |
|                       since subsequent procedures (usually SSPs) will fail if a pre-existing error condition exists.
 | |
|                       Our philosophy is that error conditions should automatically be cleared before a new procedure
 | |
|                       is executed to avoid this problem. However, the nature of Basic+ does not make this easy to
 | |
|                       automate for any given stored procedure. Therefore, if a stored procedure wants to conform to our
 | |
|                       philosophy then it should include a call into the 'Clear' service request at the top of the
 | |
|                       program. Alternatively this can be done through a common insert (see SERVICE_SETUP for example.)
 | |
| 
 | |
|                     - Service modules will use the SERVICE_SETUP insert and therefore automatically clear out any
 | |
|                       error conditions that were set before.
 | |
| 
 | |
|                     - The 'Set' service request is the equivelent to the various forms of setting an error within Basic+
 | |
|                       (e.g., Set_Status, Set_FSError, Set_EventStatus). This will clear out any pre-existing error(s)
 | |
|                       first (see 'Clear' service request description below). In most cases the 'Add' service request
 | |
|                       (see below) should be used since error conditions are intended to be automatically cleared by
 | |
|                       service modules or properly managed stored procedures.
 | |
| 
 | |
|                     - The 'Add' service request is similar to the 'Set' service request but it will not clear out any
 | |
|                       pre-existing errors. Using 'Add', the error conditions can be stacked allowing the higher level
 | |
|                       calling procedures the ability to contribute to the existing error or add additional errors.
 | |
| 
 | |
|                     - The 'Clear' service request will reset all of the error condition flags.
 | |
| 
 | |
|     Parameters  :
 | |
|         Service         [in] -- Name of the service being requested
 | |
|         Param1-10   [in/out] -- Additional request parameter holders
 | |
|         Response       [out] -- Response to be sent back to the Controller (MCP) or requesting procedure
 | |
| 
 | |
|     History     :   (Date, Initials, Notes)
 | |
|         12/28/12    dmb     Original programmer.
 | |
|         12/31/12    dmb     Add hooks for various service requests. Add comments in the Notes section to explain the
 | |
|                             theory of operation of Error Services.
 | |
|         01/01/13    dmb     Add functionality to the Set, Add, GetMessage, and GetMessages service requests.
 | |
|         01/02/13    dmb     Remove reference to SERVICES_SETUP and put the Assigned command lines directly into this
 | |
|                             code to avoid infinite loop problem.
 | |
|         01/05/13    dmb     Added HasError service request.
 | |
|         03/13/13    dmb     [SRPFW-9] Added NoError service request.
 | |
|         10/01/13    dmb     [SRPFW-18] Replace APP_INSERTS with LOGICAL and declare Error_Services.
 | |
|         10/06/13    dmb     [SRPFW-17] Retrofit to use the default FrameWorks system font.
 | |
|         03/20/17    fjt	    [SRPFW-160] Conversion to EB+; addition of justification parameter to display.
 | |
|         10/09/17    dmb     Add SendRuntimeAlert service to act as a debugger intercept process.
 | |
| 
 | |
| ***********************************************************************************************************************/
 | |
| 
 | |
| #pragma precomp SRP_PreCompiler
 | |
| 
 | |
| $Insert LOGICAL
 | |
| $Insert MSG_EQUATES
 | |
| $Insert RTI_DEBUG_COMMON
 | |
| $Insert SRPMail_Inserts
 | |
| 
 | |
| Common /ErrorServices/ ErrorMessages@, ErrorSources@, ErrorCodes@, RetStacks@, EsSpStatCode@, EsSpStatMessage@, Unused7@, Unused8@
 | |
| 
 | |
| Equ Segoe_UI$ to 'Segoe UI' : @SVM : -12 : @SVM : 400 : @SVM : 0 : @SVM : 0 : @SVM : 0 : @SVM : 0 : @SVM : 34 : @SVM : 0 : @SVM : 3 : @SVM : 2 : @SVM : 1 : @SVM : 0 : @SVM : 0 : @SVM : 0 : @SVM : 0
 | |
| 
 | |
| // Make sure any request parameters which have not been assigned are nulled.
 | |
| // Normally these would be referenced in the SERVICES_SETUP insert but there is a call to ERROR_SERVICES in that
 | |
| // insert which causes an infinite loop to occur.
 | |
| If Assigned(Service)    else Service    = ''
 | |
| If Assigned(Error)      else Error      = ''
 | |
| If Assigned(Param1)     else Param1     = ''
 | |
| If Assigned(Param2)     else Param2     = ''
 | |
| If Assigned(Param3)     else Param3     = ''
 | |
| If Assigned(Param4)     else Param4     = ''
 | |
| If Assigned(Param5)     else Param5     = ''
 | |
| If Assigned(Param6)     else Param6     = ''
 | |
| If Assigned(Param7)     else Param7     = ''
 | |
| If Assigned(Param8)     else Param8     = ''
 | |
| If Assigned(Param9)     else Param9     = ''
 | |
| If Assigned(Param10)    else Param10    = ''
 | |
| If Assigned(Response)   else Response   = ''
 | |
| 
 | |
| AutoDisplayErrors   = False$    ; // Set this to True$ when debugging so all errors will automatically display.
 | |
| 
 | |
| Declare function      RetStack, Error_Services, SRPSendMail
 | |
| Declare subroutine    Error_Services
 | |
| 
 | |
| GoToService else
 | |
| 	Error_Services('Set', Service : ' is not a valid service request within the Error services module.')
 | |
| end
 | |
| 
 | |
| Return Response else ''
 | |
| 
 | |
| 
 | |
| ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 | |
| // Service Parameter Options
 | |
| ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 | |
| Options BOOLEAN     = True$, False$
 | |
| 
 | |
| 
 | |
| ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 | |
| // Services
 | |
| ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 | |
| 
 | |
| //----------------------------------------------------------------------------------------------------------------------
 | |
| // Set
 | |
| //
 | |
| // Param1 - Error message. Messages should be fairly descriptive.
 | |
| //
 | |
| // Sets an error to the stack. This will automatically clear any existing error conditions first so this error will
 | |
| // be the only one on the stack.
 | |
| //----------------------------------------------------------------------------------------------------------------------
 | |
| Service Set(ErrorMessage)
 | |
| 
 | |
|     Error_Services('Clear')
 | |
|     Error_Services('Add', ErrorMessage)
 | |
| 
 | |
|     If AutoDisplayErrors then Error_Services('DisplayError')
 | |
| 
 | |
| End Service
 | |
| 
 | |
| 
 | |
| //----------------------------------------------------------------------------------------------------------------------
 | |
| // Add
 | |
| //
 | |
| // Param1 - Error message. Messages should be fairly descriptive.
 | |
| //
 | |
| // Adds an error to the stack. This will not clear existing error conditions first. It is intended to allow higher level
 | |
| // routines to add more information to an existing error condition or simply to maintain an ongoing error log for some
 | |
| // troubleshooting or debugging purposes.
 | |
| //----------------------------------------------------------------------------------------------------------------------
 | |
| Service Add(ErrorMessage)
 | |
| 
 | |
|     CurStack    = RetStack()
 | |
|     AtSelf      = CurStack[1, @FM]              ; // AtSelf should be the name of this routine (e.g., ERROR_SERVICES)
 | |
|     Loop
 | |
|         CurRoutine  = CurStack[1, @FM]          ; // Get the next routine from the program call stack.
 | |
|     Until CurRoutine _NEC AtSelf
 | |
|         CurStack    = Delete(CurStack, 1, 0, 0) ; // Remove any self-references from the program call stack.
 | |
|     Repeat
 | |
|     Convert @FM to @VM in CurStack              ; // Convert the delimiter so it can be added to the global common.
 | |
|     
 | |
|     If Len(ErrorMessages@) then
 | |
|         ErrorMessages@  := @FM : ErrorMessage
 | |
|         RetStacks@      := @FM : CurStack
 | |
|     end else
 | |
|         ErrorMessages@  = ErrorMessage
 | |
|         RetStacks@      = CurStack
 | |
|     end
 | |
|     
 | |
|     If AutoDisplayErrors then Error_Services('DisplayError')
 | |
| 
 | |
| End Service
 | |
| 
 | |
| 
 | |
| //----------------------------------------------------------------------------------------------------------------------
 | |
| // Clear
 | |
| //
 | |
| // Clears all error conditions and related information.
 | |
| //----------------------------------------------------------------------------------------------------------------------
 | |
| Service Clear()
 | |
| 
 | |
|     ErrorMessages@  = ''
 | |
|     ErrorSources@   = ''
 | |
|     ErrorCodes@     = ''
 | |
|     RetStacks@      = ''
 | |
| 
 | |
| End Service
 | |
| 
 | |
| 
 | |
| //----------------------------------------------------------------------------------------------------------------------
 | |
| // GetMessage
 | |
| //
 | |
| // Returns the most current error message.
 | |
| //----------------------------------------------------------------------------------------------------------------------
 | |
| Service GetMessage()
 | |
| 
 | |
|     Response = ErrorMessages@[-1, 'B' : @FM]
 | |
| 
 | |
| End Service
 | |
| 
 | |
| 
 | |
| //----------------------------------------------------------------------------------------------------------------------
 | |
| // GetMessages
 | |
| //
 | |
| // Returns the stack of error messages. This will be @FM delimited.
 | |
| //----------------------------------------------------------------------------------------------------------------------
 | |
| Service GetMessages()
 | |
| 
 | |
|     // Business logic goes here. Data that needs to be returned should be assigned to the Response parameter.
 | |
|     Response = ErrorMessages@
 | |
| 
 | |
| End Service
 | |
| 
 | |
| 
 | |
| //----------------------------------------------------------------------------------------------------------------------
 | |
| // HasError
 | |
| //
 | |
| // Returns True if there is an error condition, False if there is no error condition. Caller will still need to use
 | |
| // the GetMessage or GetMessages service to determine what the error is. The HasError service allows the caller to
 | |
| // embed the Error_Services service call inside of a conditional statement like this:
 | |
| //
 | |
| // If Error_Services('HasError') then
 | |
| //     * An error has occured. Proceed accordingly.
 | |
| //     ErrorMessage = Error_Services('GetMessage')
 | |
| // end else
 | |
| //     * No error has occured.
 | |
| // end
 | |
| //----------------------------------------------------------------------------------------------------------------------
 | |
| Service HasError()
 | |
| 
 | |
|     If Len(ErrorMessages@) then
 | |
|         Response = True$
 | |
|     end else
 | |
|         Response = False$
 | |
|     end
 | |
| 
 | |
| End Service
 | |
| 
 | |
| 
 | |
| //----------------------------------------------------------------------------------------------------------------------
 | |
| // NoError
 | |
| //
 | |
| // Returns True if there are no error conditions, False if there is an error condition. This is the opposite of the
 | |
| // HasError service and exists for improved readability.
 | |
| //----------------------------------------------------------------------------------------------------------------------
 | |
| Service NoError()
 | |
| 
 | |
|     If Len(ErrorMessages@) then
 | |
|         Response = False$
 | |
|     end else
 | |
|         Response = True$
 | |
|     end
 | |
| 
 | |
| End Service
 | |
| 
 | |
| 
 | |
| //----------------------------------------------------------------------------------------------------------------------
 | |
| // DisplayError
 | |
| //
 | |
| // Displays the current error message to the end user.
 | |
| //----------------------------------------------------------------------------------------------------------------------
 | |
| Service DisplayError(Justification)
 | |
| 
 | |
|     ErrorMessage = Error_Services('GetMessage')
 | |
|     If Len(ErrorMessage) then
 | |
|         MsgStruct                   = ''
 | |
|         MsgStruct<MTEXT$>           = ErrorMessage
 | |
|         MsgStruct<MTYPE$>           = 'BO'
 | |
|         MsgStruct<MMODAL$>          = 'W'
 | |
|         MsgStruct<MICON$>           = '!'
 | |
|         MsgStruct<MCOL$>            = -1
 | |
|         MsgStruct<MROW$>            = -1
 | |
|         MsgStruct<MJUST$>           = Justification
 | |
|         MsgStruct<MCAPTION$>        = 'Error Services'
 | |
|         MsgStruct<MFONT$>           = Segoe_UI$
 | |
|         Msg(@Window, MsgStruct)
 | |
|     end
 | |
| 
 | |
| End Service
 | |
| 
 | |
| 
 | |
| Service GetSource()
 | |
| 
 | |
|     // Business logic goes here. Data that needs to be returned should be assigned to the Response parameter.
 | |
|     Response = '<Service Response>'
 | |
| 
 | |
| End Service
 | |
| 
 | |
| 
 | |
| Service GetSources()
 | |
| 
 | |
|     // Business logic goes here. Data that needs to be returned should be assigned to the Response parameter.
 | |
|     Response = '<Service Response>'
 | |
| 
 | |
| End Service
 | |
| 
 | |
| 
 | |
| Service GetCode()
 | |
| 
 | |
|     // Business logic goes here. Data that needs to be returned should be assigned to the Response parameter.
 | |
|     Response = '<Service Response>'
 | |
| 
 | |
| End Service
 | |
| 
 | |
| 
 | |
| Service GetCodes()
 | |
| 
 | |
|     // Business logic goes here. Data that needs to be returned should be assigned to the Response parameter.
 | |
|     Response = '<Service Response>'
 | |
| 
 | |
| End Service
 | |
| 
 | |
| 
 | |
| Service GetStackTrace()
 | |
|     // Business logic goes here. Data that needs to be returned should be assigned to the Response parameter.
 | |
|     Response = '<Service Response>'
 | |
| End Service
 | |
| 
 | |
| 
 | |
| ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 | |
| // Internal GoSubs
 | |
| ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////?
 | |
| 
 | |
| //----------------------------------------------------------------------------------------------------------------------
 | |
| // SendRuntimeAlert
 | |
| //
 | |
| // Sends out an email alert when this service is called as a debugger intercept.
 | |
| //----------------------------------------------------------------------------------------------------------------------
 | |
| SendRuntimeAlert:
 | |
| 
 | |
|     Done            = False$
 | |
|     Error           = False$
 | |
|     Program         = Curr_Program@
 | |
|     MsgSent         = ''
 | |
|     
 | |
|     If Program EQ '' then Program = 'Error Services'
 | |
| 
 | |
|     ConfigFile      = ''
 | |
|     ConfigFile<1>   = SendUsing_Port$
 | |
|     ConfigFile<2>   = ''
 | |
|     ConfigFile<3>   = ''                        ; // Server port
 | |
|     ConfigFile<4>   = ''                        ; // Mail server
 | |
|     ConfigFile<5>   = True$                     ; // Authenticate
 | |
|     ConfigFile<6>   = ''                        ; // Username
 | |
|     ConfigFile<7>   = ''                        ; // Password
 | |
|     ConfigFile<8>   = False$                    ; // Use SSL
 | |
| 
 | |
|     Text        = ''
 | |
|     Text<-1>    = 'App:     '       : @APPID<1>
 | |
|     Text<-1>    = 'Window:  '       : @WINDOW
 | |
|     Text<-1>    = 'User:    '       : @USERNAME
 | |
|     Text<-1>    = 'Station: '       : @STATION
 | |
|     Text<-1>    = ' '
 | |
|     Text<-1>    = 'SP Status:    '  : SPStatus@
 | |
|     Text<-1>    = 'SP Stat Code: '  : SPStatCode@
 | |
|     Text<-1>    = 'Program:      '  : Program
 | |
|     Text<-1>    = 'Call Depth:   '  : CallDepth@
 | |
|     Text<-1>    = 'Line No:      '  : LineNo@
 | |
|     Text<-1>    = ' '
 | |
|     Text<-1>    = 'Stack:   '
 | |
|     Text<-1>    = CallStack@
 | |
|     Convert \00\ TO ',' in Text
 | |
|     Swap @VM with ':@VM:' IN Text
 | |
|     Swap @FM with Char(13) : Char(10) IN Text
 | |
|     Swap @TM with Char(13) : Char(10) IN Text
 | |
| 
 | |
|     SentFrom    = ''
 | |
|     SentTo      = ''
 | |
|     Message     = ''
 | |
|     Message<1>  = '' : Program                          ; // Subject
 | |
|     Message<2>  = SentFrom                              ; // From (email address)
 | |
|     Message<3>  = SentTo                                ; // Send to (email address)
 | |
|     Message<5>  = ''                                    ; // Blind Carbon Copy (email address)
 | |
|     Message<6>  = ''                                    ; // Reply To (email address)
 | |
|     Message<7>  = 'TEXT'                                ; // Content Type (TEXT or HTML)
 | |
|     Message<8>  = Text                                  ; // Content / Body
 | |
|     Message<9>  = ''                                    ; // Attachment(s) (path to file name(s))
 | |
| 
 | |
|     MsgSent     = SRPSendMail(Message, ConfigFile)
 | |
| 
 | |
| return
 | |
| 
 |