example section;
authorClaus Gittinger <cg@exept.de>
Wed, 15 Jan 1997 21:11:02 +0100
changeset 2174 3c6300f27f74
parent 2173 01ad5ffe0c9d
child 2175 a3fe5ef27022
example section; added useful emergencyHandler section
Exception.st
--- a/Exception.st	Wed Jan 15 19:08:31 1997 +0100
+++ b/Exception.st	Wed Jan 15 21:11:02 1997 +0100
@@ -112,6 +112,48 @@
     [author:]
         Claus Gittinger
 "
+!
+
+examples
+"
+    Examples on Exception-raising & handling are found in the doc/coding
+    section (CodingExamples).
+
+    The emergencyHandler stuff is very useful, to prevent endUser applications
+    from entering the debugger.
+    Some commonly used (useful) emergency handlers are provided in the
+    'useful handlers' section; try them to learn more
+    (especially, the mailingHandler is fun).
+
+    Define a handler:
+                                                                [exBegin]
+        Exception emergencyHandler:(Exception abortingEmergencyHandler)
+                                                                [exEnd]
+
+
+    try some exception (for demonstration, in some other process):
+                                                                [exBegin]
+        [
+            #(1 2 3) at:4
+        ] fork.
+                                                                [exEnd]
+
+    cleanup:
+                                                                [exBegin]
+        Exception emergencyHandler:nil
+                                                                [exEnd]
+
+
+    A handler which dumps information to a file (watch the file 'errorTrace.stx'):
+                                                                [exBegin]
+        Exception emergencyHandler:(Exception dumpingEmergencyHandler)
+                                                                [exEnd]
+
+    A handler which sends you mail:
+                                                                [exBegin]
+        Exception emergencyHandler:(Exception mailingEmergencyHandler)
+                                                                [exEnd]
+"
 ! !
 
 !Exception class methodsFor:'initialization'!
@@ -163,28 +205,37 @@
 !Exception class methodsFor:'defaults'!
 
 emergencyHandler
-    "return the handler used for unhandled exceptions"
+    "return the handler used for unhandled exceptions.
+
+     If no EmergencyHandler has been set, a handler which enters the 
+     debugger is returned.
+     The debugger is opened by asking the signal for a debug action,
+     this allows to provide other debuggers in specialized (subclass-instances)
+     of Signal (if that is ever needed)"
 
     "
      set it up, when called the first time
     "
     EmergencyHandler isNil ifTrue:[
-	EmergencyHandler := [:ex |
-	    "
-	     sending it to the signal allows per-signal specific
-	     debuggers to be implemented in the future
-	     (for example, segv in primitive code could show things 
-	      on the C-level ..)
-	    "
-	    (ex signal) enterDebuggerWith:ex message:(ex errorString).
-	]
+        EmergencyHandler := [:ex |
+            "
+             sending it to the signal allows per-signal specific
+             debuggers to be implemented in the future
+             (for example, segv in primitive code could show things 
+              on the C-level ..)
+            "
+            (ex signal) enterDebuggerWith:ex message:(ex errorString).
+        ]
     ].
 
     ^ EmergencyHandler
+
+    "Modified: 15.1.1997 / 20:50:37 / cg"
 !
 
 emergencyHandler:aOneArgBlock
-    "set the handler used for unhandled exceptions"
+    "set the handler used for unhandled exceptions.
+     The default (a nil-handler) leads to a debugger to be shown."
 
     EmergencyHandler := aOneArgBlock
 
@@ -218,7 +269,214 @@
             [:ex | Smalltalk exitWithCoreDump. ]
     "
 
-    "Modified: 7.1.1997 / 21:15:07 / cg"
+    "Modified: 15.1.1997 / 20:49:06 / cg"
+! !
+
+!Exception class methodsFor:'useful handlers'!
+
+abortingEmergencyHandler
+    "return a block (usable as an emergency handler), 
+     which aborts after showing a warnBox.
+     This is useful for endUser applications"
+
+    ^ [:ex | self warn:'Error: ' , ex errorString.
+             AbortSignal raise 
+      ]
+
+    "test with (try a few halts or CTRL-C's):
+     Exception emergencyHandler:(Exception abortingEmergencyHandler)
+    "
+
+    "back with:
+     Exception emergencyHandler:(Exception notifyingEmergencyHandler)
+     Exception emergencyHandler:nil
+    "
+
+    "Created: 15.1.1997 / 20:13:06 / cg"
+    "Modified: 15.1.1997 / 20:15:02 / cg"
+!
+
+dumpingEmergencyHandler
+    "return a block (usable as an emergency handler), 
+     which dumps the stackBacktrace to a trace file and
+     aborts after showing a warnBox.
+     This is useful, for endUser application, which are still being
+     debugged (i.e. the programmers may have a look at the traceFile
+     from time to time).
+
+     Notice:
+         The code below is just an example; you may want to change the
+         name of the error-file in your application
+         (but please: copy the code; do not modify here)"
+
+    ^ [:ex | 
+             |str printedException|
+
+             ex signal == Signal noHandlerSignal ifTrue:[
+                printedException := ex parameter.
+             ] ifFalse:[
+                printedException := ex
+             ].
+
+             "/ user interruption is handled specially:
+             "/ allow user to choose between proceeding or aborting
+             "/ but never dump that information to the file.
+
+             printedException signal == Object userInterruptSignal ifTrue:[
+                  (self confirm:'abort current action ?') ifTrue:[
+                      AbortSignal raise
+                  ].
+                  ex proceed
+             ].
+
+             "/
+             "/ dump it to 'errorTrace.stx'
+             "/
+             str := 'errorTrace.stx' asFilename appendingWriteStream.
+
+             str nextPutLine:('******************************* '
+                              , AbsoluteTime now printString
+                              , ' *******************************').
+             str cr.
+
+             str nextPutLine:('** Error: ' , printedException errorString).
+             str nextPutLine:('** Signal: ' , printedException signal printString).
+             str nextPutLine:('** Parameter: ' , printedException parameter printString).
+             str nextPutLine:('** Process: ' , Processor activeProcess printString).
+             str nextPutLine:('** Backtrace:').
+             str cr.
+        
+             printedException suspendedContext fullPrintAllOn:str.
+             str cr.
+             str cr.
+             str close.
+
+             self warn:printedException errorString.
+             AbortSignal raise 
+      ]
+
+    "test with (try a few halts or CTRL-C's):
+     Exception emergencyHandler:(Exception dumpingEmergencyHandler)
+    "
+
+    "back with:
+     Exception emergencyHandler:(Exception notifyingEmergencyHandler)
+     Exception emergencyHandler:nil
+    "
+
+    "Created: 15.1.1997 / 20:14:52 / cg"
+    "Modified: 15.1.1997 / 21:07:14 / cg"
+!
+
+mailingEmergencyHandler
+    "return a block (usable as an emergency handler), 
+     which shows a warnBox and optionally mails a stackBacktrace to a maintainer.
+     This is useful, for endUser application, which are still being
+     debugged (i.e. the programmers may have a look at the errors).
+
+     Notice: the stuff here is a demonstration only; it should be modified
+             for your particular environment ...
+             ... but please: copy the code and modify there;
+             leave the stuff below as it is."
+
+    ^ [:ex | 
+            |str printedException doMail emergencyMailReceiver pipe|
+
+            ex signal == Signal noHandlerSignal ifTrue:[
+               printedException := ex parameter.
+            ] ifFalse:[
+               printedException := ex
+            ].
+
+             "/ user interruption is handled specially:
+             "/ allow user to choose between proceeding or aborting
+             "/ but never dump that information to the file.
+
+             printedException signal == Object userInterruptSignal ifTrue:[
+                  (self confirm:'abort current action ?') ifTrue:[
+                      AbortSignal raise
+                  ].
+                  ex proceed
+             ].
+
+            "/ somehow get the name of the guy to receive the mail
+            "/ you have to implement that yourself.
+
+            "/ emergencyMailReceiver := OneOfYourClass getEmergencyMailReceiver.
+            emergencyMailReceiver := OperatingSystem getLoginName.
+
+            emergencyMailReceiver isNil ifTrue:[
+                self warn:(printedException errorString 
+                           , '\\No mailing to service people possible.') withCRs.
+                doMail := false.
+            ] ifFalse:[
+                doMail := self confirm:(printedException errorString 
+                                        , '\\Mail error information to the service people (' 
+                                        , emergencyMailReceiver , ') ?') withCRs
+            ].
+            doMail ifTrue:[
+                str := '' writeStream.
+
+                str nextPutLine:('Error notification from '
+                                , OperatingSystem getLoginName
+                                , '@'
+                                , OperatingSystem getHostName).
+                str cr.
+
+                str nextPutLine:('Time: ' , AbsoluteTime now printString).
+                str nextPutLine:('Error: ', printedException errorString).
+                str nextPutLine:('Signal: ', printedException signal printString).
+                str nextPutLine:('Parameter: ', printedException parameter printString).
+                str nextPutLine:('Process: ', Processor activeProcess printString).
+                str nextPutLine:'Backtrace:'.
+                str cr.
+
+                printedException suspendedContext fullPrintAllOn:str.
+                str cr;cr.
+
+                str close.
+
+                pipe := PipeStream 
+                            writingTo:'mail ', emergencyMailReceiver.
+                pipe notNil ifTrue:[
+                    pipe nextPutLine:'Subject: automatic error report'.
+                    pipe nextPutAll:str contents.
+                    pipe cr.
+                    pipe close.
+                ]
+             ].
+
+             AbortSignal raise 
+      ]
+
+    "test with (try a few halts or CTRL-C's):
+     Exception emergencyHandler:(Exception mailingEmergencyHandler)
+    "
+
+    "back with:
+     Exception emergencyHandler:(Exception notifyingEmergencyHandler)
+     Exception emergencyHandler:nil
+    "
+
+    "Created: 15.1.1997 / 20:14:52 / cg"
+    "Modified: 15.1.1997 / 21:10:28 / cg"
+!
+
+notifyingEmergencyHandler
+    "return a block (usable as an emergency handler for exceptions), 
+     which does errorNotification before going into the debugger."
+
+    ^ [:ex | nil errorNotify:ex errorString from:ex suspendedContext ]
+
+    "test with (try a few halts or CTRL-C's):
+     Exception emergencyHandler:(Exception notifyingEmergencyHandler)
+    "
+
+    "back with:
+     Exception emergencyHandler:nil
+    "
+
+    "Modified: 15.1.1997 / 20:15:12 / cg"
 ! !
 
 !Exception methodsFor:'accessing'!
@@ -607,6 +865,6 @@
 !Exception class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libbasic/Exception.st,v 1.43 1997-01-07 20:42:18 cg Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic/Exception.st,v 1.44 1997-01-15 20:11:02 cg Exp $'
 ! !
 Exception initialize!