I have a simple database connection method that I want to add a condition that if the connection fails then an email is sent to a list of people telling that it failed to connect.
My current method is this:
public Connection createInitialConnection() throws ClassNotFoundException, SQLException, PollingException
{
DBConnectionDetails conDetails = new DBConnectionDetails("INITIAL");
Class.forName(conDetails.getDriver());
Connection connInitial = DriverManager.getConnection(conDetails.getUrl(),
conDetails.getUser(), conDetails.getPassword());
logger.info("Initial connection created" + conDetails.getUrl());
return connInitial;
}
Currently, there is no checking to see if the connection was successful, if it does not connect then the program just keeps going.
I'm not sure about the best way to do this would be. An if/else or try/catch?
Logging libraries like log4j allow you to add a logging appender that sends emails for each log entry (of course you can filter by severity, category, etc.). So when you attempt to get a connection and an exception is thrown it should get caught by the exception handler and logged, and the logger will send emails.
That assumes your application has some kind of exception handler that logs uncaught exceptions. Where that happens depends on your application's architecture. It could be in a servlet, in try-catch code in the jsp, or in a dedicated handler in a webapp framework like struts or spring-mvc.
If you implement this you will have a way to be notified when any exceptions are getting logged, it won't be limited to database connectivity problems.
You can send email on catch block.
try{
Class.forName(conDetails.getDriver());
Connection connInitial = DriverManager.getConnection(conDetails.getUrl(),
conDetails.getUser(), conDetails.getPassword());
}
catch(SQLException | ClassNotFoundException ex){ // Java 7 needed for multicatch
// Send the Email.
}
Maybe you should try to catch SQLExcepton and then, send notification like this :
try {
Connection connInitial = DriverManager.getConnection(conDetails.getUrl(), conDetails.getUser(), conDetails.getPassword());
} catch (SQLException e) {
//send notification here
}
catch block. It is always better than if-else
try{
// your Logic to test the connection
}
catch(Exception ex)
{
//Code to send the mail if the connection is failed.
}
You can do with try { } Catch .. This in case you have an execption like no network or somthing. after that you need to check if Connection != null.. This is all you need
Sending an email in the catch block might be OK for your application, but then you're faced with how to configure the email. Who should receive it? Are multiple recipients possible? How should the senders, subject and format be configured and passed to your mailer? What if the mailer fails? You may find yourself reinventing an existing solution if you go that route.
If you're using Log4j, it might be a good idea to configure a SMTPAppender for your existing logger or create a logger for errors which need to be sent over email. You can configure Log4j to use the appender for only SQL exceptions if you like (ie. log4j: Log output of a specific class to a specific appender).
Related
When having declared a method like this using Spring AMQP:
#RabbitListener(..)
public void myMethod(#Header(AmqpHeaders.CHANNEL) Channel channel, #Header(AmqpHeaders.DELIVERY_TAG) Long tag, ...)
and using manual acknowledge mode, how should one properly deal with the IOException that may be thrown when doing ACK:
try {
channel.basicAck(tag, false);
} catch (IOException e) {
// What to do here?
}
Should the exception be rethrown? Should the "basicAck" operation be retried? What's the proper way to handle it?
The standard way of doing this is using retry mechanism & to come out if none of them succeeds.
However, based on my experience, if channel throws an exception, it more or less means the channel is useless & you might have to redo the whole thing again. I normally log the error along with the required details so that I can track which message processing failed so that I can verify the same later to see if its processed or I need to do anything about it.
I am using Apache Camel with Spring to send messages from my Java service. I need to handle/trigger certain events in case of any error occurred at exchange. I am using below code to achieve my objective.
try
{
producerTemplate.sendBody(endPoint, bytes);
}
catch (final RuntimeCamelException exception)
{
LOGGER.error("Exception occured in sendBody", exception.getMessage(), exception);
handleError(); // handle error here.
}
In order to test I set the value of endPoint to incorrect route name broadcast.SIMULATOR.ROUTE1. When I am running above code, I can see following error in console but it never comes inside catch block.
[33m16:15:51,714 WARN [org.springframework.jms.connection.CachingConnectionFactory] (QpidJMS Connection Executor: ID:7dacac8c-93ce-48c0-92fe-8dc0e8:1) Encountered a JMSException - resetting the underlying JMS Connection: javax.jms.JMSSecurityException: Admin#QPID9019 cannot publish to broadcast with routing-key broadcast.SIMULATOR.ROUTE1 (/builddir/build/BUILD/qpid-cpp-1.36.0/src/qpid/broker/amqp/Authorise.cpp:126) [condition = amqp:unauthorized-access]
at org.apache.qpid.jms.provider.amqp.AmqpSupport.convertToException(AmqpSupport.java:143) [qpid-jms-client-0.23.0.jar:]
at org.apache.qpid.jms.provider.amqp.AmqpSupport.convertToException(AmqpSupport.java:117) [qpid-jms-client-0.23.0.jar:]
I am sending multiple messages to the route. For first message, JMSSecurityException is logged in console and execution continues. From second message onwards, execution goes inside catch with IllegalStateException (Session is closed) .
How do I bring execution inside catch block with first message only (for JMSSecurityException)?
It depends on the JMS client you are using. As some of them send the message in an asynchronous fashion. They may have a configuration option you can use to turn this off.
For example Apache ActiveMQ has this with asyncSend option
http://activemq.apache.org/async-sends.html which you can then turn off.
I am working on a basic Java command line email client application. The connector I was provided with will send me emails, however if I "send" an email it will not be located on the connector as I created this email myself. Now when I want to delete an email I can find the folder I am in and delete it by its ID. I also want to delete it from the connector if its located inside the connector so that I will not receive this email again when I refresh emails.
public boolean delete(int messageId) throws IndexOutOfBoundsException
{
if (folders.get(getActiveFolderName()).delete(messageId))
{
if (connector.retrMessage(messageId) != null)
{
connector.markMessageForDeleting(messageId);
//throws exception if not found on connector
}
return true;
}
return false;
}
I tried this, is this a really bad way of going about handling exceptions?:
public boolean delete(int messageId)
{
if (folders.get(getActiveFolderName()).delete(messageId))
{
try{
connector.markMessageForDeleting(messageId);
} catch (IndexOutOfBoundsException e)
{
//this successfully soaks up the exception if its not located in connector
}
return true;
}
return false;
}
Thanks
Though they are considered as bad, as long as you are aware of what's going on and took necessary steps to recover from abnormal behaviour of the program, it will be fine.
I'm just suggesting to you to put at least a log statement.
I would personally not think so. You are using the exception as an indicator of a particular result. You're not trying to hide some error in the code by not doing anything when you catch it. However, I'm not sure if you have the ability to change anything about this connector, but if so, you should adjust it so it isn't throwing errors like that in the first place.
What you're doing is called exception swallowing. It's generally considered bad practice. The risk is to swallow exceptions that might happen when your emails are located in the connector. You don't want that.
You already know a reason to have an IndexOutOfBoundsException, so why not test first if your email is located in the connector?
It is always good practice to log any exception & then can be ignored in the cases like yours.
P.S.: No need to flood the log with stack trace in your case. It can be a simple error message indicating that the exception can be ignored safely.
Historical Context: This problem ended up being not at all what I thought it was. The cause and solution are below, but the original posting is left for reference.
I'm developing a simple framework for periodically polling a directory for .properties files, then performing SQL queries and sending e-mails based on their configurations. Because each .properties file has the same spectrum of operations, they are all interpreted by the same Task class. But since they each represent different logical operations, they each get separate log files.
This is accomplished by sharing one instance of a log4j RollingFileAppender, and dynamically changing its output file based on a value in the .properties file. Since this is a single-threaded application, this works fine.
However, I've noticed that in certain situations, this RollingFileAppender will become closed, and the application will continue on obliviously except that now no logging takes place. I've only managed to catch this in action once, thanks to the console output, since usually this service is running as a background process on a Linux server. Here's what happened:
1) StartScheduler, the main class, creates a new instance of TaskPoller every minute.
2) TaskPoller scans the directory, loads a little information from each .properties file, and determines if it should be run. It also has its own separate RollingFileAppender, which it retrieves via Logger.getLogger(TaskPoller.class). If a Task should be run, then it instantiates a Task object, passing in the specific .properties file to be run.
3) Task gets its RollingFileAppender, then calls fileAppender.setFile("newtaskname.log") and fileAppender.activateOptions() to change the output file location. Then, during its execution, something like this happens:
[TaskPoller]
...
task = new Task(fileName); //Points RollingFileAppender to the right place
if (!task.Execute())
logger.warn(fileName + " returned with an error code."); //Succeeds
[Task.Execute]
...
try {
dbDAO.Connect();
} catch (Exception e) {
logger.fatal{"Database connection error.", e}; //Different RFA; Fails
return false;
}
[DBDAO.Connect throws SQLException, ClassNotFoundException]
...
try {
Class.forName(dbDriver); //Dynamically loaded jdbc driver class name
connection = DriverManager.getConnection(urlString, userName, password);
} catch (SQLException e) {
if (connection != null)
try { connection.close(); } catch (Exception e2) { ; }
throw e;
}
What's happening is that during DBDAO.Connect(), sometimes I'll get a com.mysql.jdbc.exceptions.jdbc4.CommunicationsException (or some other unexpected exception from whichever jdbc class is loaded). This will not be caught by Connect(), but it will be caught by Execute().
Somehow, this process causes Task's RollingFileAppender to become closed. The only thing I can think of that's special to this situation, as opposed to its consistent and stable normal operation, is that the exception being thrown isn't declared as thrown by Connect(). But I don't think that should cause a log4j Appender to close.
So my question is, what could be causing this appender to unexpectedly close in methods that have nothing to do with its configuration?
--Edit--
It looks like I've been misdirected entirely; the problem is somewhere in the interactions between Quartz, which I was using to have TaskPoller fire every minute, and log4j. I don't entirely understand its cause yet, but [this solution][1] seems to solve this problem. It just didn't manifest itself as an observed problem until now, so I thought it had something to do with what was happening recently.
The real cause of this problem is an interaction between the Quartz scheduler and the way I was using log4j. It turns out, if you modify log4j's properties (which I was doing by calling fileAppender.setFile(fileName) and fileAppender.activateOptions()) on a Quartz worker thread (even if Quartz is configured to only have a single thread running at a time), things break down. This is fixed by reloading the log4j properties on each new instance of the worker thread before using it, which I accomplished like so:
[Task() Constructor]
Properties props = new Properties();
URL url = ClassLoader.getSystemResource("log4j.properties");
try {
props.load(url.openStream());
PropertyConfigurator.configure(props);
} catch (Exception e) {
//The logger that never got renamed never stopped working.
Logger.getLogger(TaskPoller.class).error("Diagnostics!");
}
logger = Logger.getLogger(Task.class);
I have written a java class where if a method throws an exception, an email is sent, via java mail, with a report to the administrators.
It works - my question is w.r.t elegance - to catch the exception thrown by the main method, the sendEmail() method resides in the catch block of the main method. The sendEmail() method has its own try-catch block.
In effect - it looks like below - is there a more beautiful way of writing this?
try {
foo;
}
catch {
try{
sendEmail();
}
catch {
log(e.message);
}
}
If you want something "more elegant", one simple suggestion is to have your sendEmail helper method catch and log the email exceptions. (I don't imagine you want the exceptions to propagate ... or do some other recovery ...)
However, there is something more important to say. What you are implementing here is the wrong approach to reporting errors.
If something goes badly wrong with your application there is a chance that you will SPAM the administrator with multiple emails reporting the same problem over, and over, and over ...
By sending emails from deep within your code, you are making it hard for the administrator to integrate your application's error reporting.
A better approach is to report the problem via a Java logging frame such as Log4J. If the administrator wants to he / she can configure some kind of monitoring system like LogWatch, Nagios, etc, etc. Such a monitoring system will detect and classify errors, anomalies, etc (like your application's errors) in the various logger streams, de-dup them, and if the administrator configures it send a notification via email, pager or whatever.
Java can have nested try / catch blocks.
If you'd like, you can move the try / catch sendmail block to another method. When the try / catch blocks are more complex, it will make the code easier to understand.