I've read some beginner's introductions to smalltalk and there is one topic that's missing. It's error handling. How is it done? Do objects throw some kind of exceptions? Send some error messages to someone?
To raise an exception:
MyException signal.
MyException signal: 'With an error message'.
To handle an exception:
[ 1 / 0 ] on: ZeroDivide do: [ Transcript showln: 'Oops! Zero divide!'].
To handle an exception and use some of the exception's information:
[ 1 / 0 ] on: Error do:
[:e | Transcript showln: 'Oops! ' , e className , '!'].
To ensure something always happens (a la try finally):
[ 1 / 0 ] ensure: [ Transcript showln: 'This will always run' ]
I just want to point out that beside the way #Frank Shearar mention there is an other possibility. I mean by design. Sometime is more useful to let the caller now what trouble is going throw.
The #on:do: is perfectly acceptable but most of the time you don't know what to put as a first argument. block on: ?? do: something.
Let take me an example. Actually there is an example from the Collection library. Especially regarding dictionary.
aDict at: 4
Here what happen if 4 isn't in the dictionary. You just get a plain Error that you need to catch in a #on:do:.
But there is a better way to handle this situation:
aDict at: 4 ifAbsent: [^#noSuchThingAs4]
You are handle the error the same as the #on:do: but now you know why.
So you could do that in other to handle properly your error.
aConnection connectIfFailed: [ ^#maybeRetryHere ]
Be aware that you need to put the exception code in a block so that it won't be evaluate until the error happen.
aDict at: 4 ifAbsentPut: self default
may work but it is wrong. Hope that help you.
Read the Pharo By Example 2 chapter: https://gforge.inria.fr/frs/download.php/26600/PBE2-Exceptions-2010-03-02.pdf
Related
I'm trying to write a script to test all DataSources of a WebSphere Cell/Node/Cluster. While this is possible from the Admin Console a script is better for certain audiences.
So I found the following article from IBM https://www.ibm.com/support/knowledgecenter/en/SSAW57_8.5.5/com.ibm.websphere.nd.multiplatform.doc/ae/txml_testconnection.html which looks promising as it describles exactly what I need.
After having a basic script like:
ds_ids = AdminConfig.list("DataSource").splitlines()
for ds_id in ds_ids:
AdminControl.testConnection(ds_id)
I experienced some undocumented behavior. Contrary to the article above the testConnection function does not always return a String, but may also throw a exception.
So I simply use a try-catch block:
try:
AdminControl.testConnection(ds_id)
except: # it actually is a com.ibm.ws.scripting.ScriptingException
exc_type, exc_value, exc_traceback = sys.exc_info()
now when I print the exc_value this is what one gets:
com.ibm.ws.scripting.ScriptingException: com.ibm.websphere.management.exception.AdminException: javax.management.MBeanException: Exception thrown in RequiredModelMBean while trying to invoke operation testConnection
Now this error message is always the same no matter what's wrong. I tested authentication errors, missing WebSphere Variables and missing driver classes.
While the Admin Console prints reasonable messages, the script keeps printing the same meaningless message.
The very weird thing is, as long as I don't catch the exception and the script just exits by error, a descriptive error message is shown.
Accessing the Java-Exceptions cause exc_value.getCause() gives None.
I've also had a look at the DataSource MBeans, but as they only exist if the servers are started, I quickly gave up on them.
I hope someone knows how to access the error messages I see when not catching the Exception.
thanks in advance
After all the research and testing AdminControl seems to be nothing more than a convinience facade to some of the commonly used MBeans.
So I tried issuing the Test Connection Service (like in the java example here https://www.ibm.com/support/knowledgecenter/en/SSEQTP_8.5.5/com.ibm.websphere.base.doc/ae/cdat_testcon.html
) directly:
ds_id = AdminConfig.list("DataSource").splitlines()[0]
# other queries may be 'process=server1' or 'process=dmgr'
ds_cfg_helpers = __wat.AdminControl.queryNames("WebSphere:process=nodeagent,type=DataSourceCfgHelper,*").splitlines()
try:
# invoke MBean method directly
warning_cnt = __wat.AdminControl.invoke(ds_cfg_helpers[0], "testConnection", ds_id)
if warning_cnt == "0":
print = "success"
else:
print "%s warning(s)" % warning_cnt
except ScriptingException as exc:
# get to the root of all evil ignoring exception wrappers
exc_cause = exc
while exc_cause.getCause():
exc_cause = exc_cause.getCause()
print exc_cause
This works the way I hoped for. The downside is that the code gets much more complicated if one needs to test DataSources that are defined on all kinds of scopes (Cell/Node/Cluster/Server/Application).
I don't need this so I left it out, but I still hope the example is useful to others too.
I'm using the Slim Framework.
Most PHP errors in my application output normal PHP error messages
Example code with an error that outputs the Call Stack:
echo 'missing semicolon at eol'
Error Output:
Parse error: syntax error, unexpected T_IF, expecting ',' or ';' in /data/www/app/routes/companies_routes.php on line 737
Call Stack:
0.0002 637144 1. {main}() /data/www/html/index.php:0
But other errors ( maybe just notices ) output a limited message that doesn't have a line number, file name, or call stack. This makes debugging these errors extremely time consuming.
Code with an error that outputs a limited error message
echo $an_undefined_variable;
Limited Message
Undefined variable: an_undefined_variable
I can't figure out what's going on. I've never had this problem before. I suspect it has something to do with the way Slim handles PHP errors. I've tried wrapping these errors in Try/Catch blocks, but that doesn't solve the problem.
The problem is that Slim is handling exceptions itself ( some sort of default behavior I've yet to track down ).
I've got my code wrapped in Try/Catch blocks, so when Slim catches a PHP error, it's throwing it's own Exception that I'm then outputting in my Catch block. If I remove my Catch block, Slim them outputs it's own complete error message that contains the stack as usual.
This surely means I'm not using Slim quite right, but that's a different question.
I've got some code to parse an XML file like this:
[doc := (XML.XMLParser new) parse: aFilename asURI] on: XML.SAXParseException
do: [:ex | MyCustomError raiseSignal: ex description].
I now want to handle the MyCustomError higher in the stack, by moving the XML file to a folder named 'Failed', but I get a sharing violation error because the parser has not had the opportunity to close the file.
If I alter my code like this it works, but I wonder if there is a better way:
[doc := (XML.XMLParser new) parse: aFilename asURI] on: XML.SAXParseException
do: [:ex | description := ex description].
description ifNotNil: [MyCustomError raiseSignal: description].
Code can signal an exception for errors which are resumable (non-fatal); if you trap such an error you can't be certain that the XMLParser isn't intending to keep on going. For example, code that doesn't know whether it's being called in interactive or batch mode might signal an exception for a simple informational message; the caller would know whether to handle it in an interactive way (say with a message prompt) or a batch way (writing a message to a log file).
In order for this to work the pieces of code that are communicating in this way have to know what sort of an error it is they're dealing with. (This would typically be done with a severity level, encoded either by state in the exception object or by raising a different class of exception.) If you inspect the ex object you might be able to see this information.
In any case, the evidence suggests that XMLParser is treating SAXParseException as a resumable error (otherwise, it should clean up after itself). That being so, your "fix" seems appropriate enough.
you can also run the parser on a ReadStream instead of a URL. Then you can wrap your code in an ensure block where you close the readStream.
I am getting an error:
java.lang.NullPointerException
When I call:
<cfdump var="#posts#" top="2">
<cfset postsQuery = EntityToQuery(posts)>
dumping posts shows an array of objects as it should but for some reason the EntityToQuery(posts) is breaking. The error message is not one of the normal ones which tell you what line it broke on etc. its just the following struct:
message: [empty string]
StackTrace: java.lang.NullPointerException
TagContext: array[empty]
Type: java.lang.NullPointerException
Does anyone have any idea what could cause this? I think its data related but I don't know what to look for. Its only happening on one implementation of this code, not the others im working on.
Strange errors stopped the next time the coldfusion service was restarted.
So if anyone else has that problem.... give restarting cf a try
"The action of the default handlers is to print an explanatory message and exit." (link)
Example of such message:
X Error of failed request: BadWindow (invalid Window parameter)
Major opcode of failed request: 12 (X_ConfigureWindow)
Resource id in failed request: 0xc0007a
Serial number of failed request: 140
Current serial number in output stream: 141
If I set (XSetErrorHandler) my own "ignore everything" error handler, the "explanatory messages" disappear.
How to make Xlib ignore errors, but still print error messages?
If you actually want those error messages you pretty much have two options:
Pull _XPrintDefaultError out of XlibInt.c along with some private headers (with all the caveats of using library-private definitions).
Redefine exit() not to actually exit when _XDefautError calls it.
Neither is especially pretty and both may break and reduce your portability, but they do work.
You have to format your own message. The contents of the message is the contents of the XErrorEvent struct:
http://tronche.com/gui/x/xlib/event-handling/protocol-errors/default-handlers.html