/*******************************************************************************
* This file is part of OpenNMS(R).
*
* Copyright (C) 2006-2011 The OpenNMS Group, Inc.
* OpenNMS(R) is Copyright (C) 1999-2011 The OpenNMS Group, Inc.
*
* OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc.
*
* OpenNMS(R) is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* OpenNMS(R) is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenNMS(R). If not, see:
* http://www.gnu.org/licenses/
*
* For more information contact:
* OpenNMS(R) Licensing <license@opennms.org>
* http://www.opennms.org/
* http://www.opennms.com/
*******************************************************************************/
package org.opennms.netmgt.poller.monitors;
import java.net.InetAddress;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.Driver;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Map;
import java.util.Properties;
import org.apache.log4j.Level;
import org.opennms.core.utils.DBTools;
import org.opennms.core.utils.ParameterMap;
import org.opennms.core.utils.TimeoutTracker;
import org.opennms.netmgt.model.PollStatus;
import org.opennms.netmgt.poller.Distributable;
import org.opennms.netmgt.poller.MonitoredService;
import org.opennms.netmgt.poller.NetworkInterface;
import org.opennms.netmgt.poller.NetworkInterfaceNotSupportedException;
/**
* This class implements a basic JDBC monitoring framework; The idea is than
* these tests doesn't take too long (or too much resources to run) and provide
* the basic healt information about the polled server. See
* <code>src/services/org/opennms/netmgt/poller</code> OpenNMS plugin
* information at <a
* href="http://www.opennms.org/users/docs/docs/html/devref.html">OpenNMS
* developer site </a>
*
* @author Jose Vicente Nunez Zuleta (josevnz@users.sourceforge.net) - RHCE,
* SJCD, SJCP version 0.1 - 07/23/2002 * version 0.2 - 08/05/2002 --
* Added retry logic, input validations to poller.
* @since 0.1
* @version $Id: $
*/
// NOTE: This requires that the JDBC Drivers for the dbs be included with the remote poller
@Distributable
public class JDBCMonitor extends AbstractServiceMonitor {
/**
* Number of miliseconds to wait before timing out a database login using
* JDBC Hint: 1 minute is 6000 miliseconds.
*/
public static final int DEFAULT_TIMEOUT = 3000;
/**
* Default number of times to retry a test
*/
public static final int DEFAULT_RETRY = 0;
/**
* Class constructor.
*
* @throws java.lang.ClassNotFoundException if any.
* @throws java.lang.InstantiationException if any.
* @throws java.lang.IllegalAccessException if any.
*/
public JDBCMonitor() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
log().info("JDBCmonitor class loaded");
}
/**
* {@inheritDoc}
*
* This method is called after the framework loads the plugin.
*/
public void initialize(Map<String, Object> parameters) {
super.initialize(parameters);
log().debug("Calling init");
}
/**
* Release any used services by the plugin,normally during framework exit
* For now this method is just an 'adaptor', does nothing
*
* @throws java.lang.RuntimeException
* Thrown if an error occurs during deallocation.
*/
public void release() {
log().debug("Shuting down plugin");
}
/**
* This method is called when an interface that support the service is added
* to the scheduling service.
*
* @throws java.lang.RuntimeException
* Thrown if an unrecoverable error occurs that prevents the
* interface from being monitored.
* @throws org.opennms.netmgt.poller.NetworkInterfaceNotSupportedException
* Thrown if the passed interface is invalid for this monitor.
* @param svc a {@link org.opennms.netmgt.poller.MonitoredService} object.
*/
public void initialize(MonitoredService svc) {
super.initialize(svc);
log().debug("initialize");
}
/**
* {@inheritDoc}
*
* <P>
* This method is the called whenever an interface is being removed from the
* scheduler. For now this method is just an 'adaptor', does nothing
*/
public void release(MonitoredService svc) {
log().debug("Shuting down plugin");
}
/**
* {@inheritDoc}
*
* Network interface to poll for a given service. Make sure you're using the
* latest (at least 5.5) <a
* href="http://www.sybase.com/detail_list/1,6902,2912,00.html">JConnect
* version </a> or the plugin will not be able to tell exactly if the
* service is up or not.
* @see org.opennms.netmgt.poller.ServiceMonitor#SERVICE_AVAILABLE
* @see org.opennms.netmgt.poller.ServiceMonitor#SERVICE_UNAVAILABLE
* @see org.opennms.netmgt.poller.ServiceMonitor#SERVICE_UNRESPONSIVE
* @see org.opennms.netmgt.poller.ServiceMonitor#SERVICE_AVAILABLE
* @see org.opennms.netmgt.poller.ServiceMonitor#SERVICE_UNAVAILABLE
* @see org.opennms.netmgt.poller.ServiceMonitor#SERVICE_UNRESPONSIVE
* @see org.opennms.netmgt.poller.ServiceMonitor#SERVICE_AVAILABLE
* @see org.opennms.netmgt.poller.ServiceMonitor#SERVICE_UNAVAILABLE
* @see org.opennms.netmgt.poller.ServiceMonitor#SERVICE_UNRESPONSIVE
* @see <a
* href="http://manuals.sybase.com/onlinebooks/group-jc/jcg0550e/prjdbc/@Generic__BookTextView/9332;pt=1016#X">Error
* codes for JConnect </a>
*/
public PollStatus poll(MonitoredService svc, Map<String, Object> parameters) {
NetworkInterface<InetAddress> iface = svc.getNetInterface();
// Assume that the service is down
PollStatus status = PollStatus.unavailable();
Driver driver = null;
Connection con = null;
Statement statement = null;
ResultSet resultset = null;
if (iface.getType() != NetworkInterface.TYPE_INET) {
log().error("Unsupported interface type, only TYPE_INET currently supported");
throw new NetworkInterfaceNotSupportedException(getClass().getName() + ": Unsupported interface type, only TYPE_INET currently supported");
}
if (parameters == null) {
throw new NullPointerException("parameter cannot be null");
}
try {
String driverClass = ParameterMap.getKeyedString(parameters, "driver", DBTools.DEFAULT_JDBC_DRIVER);
driver = (Driver)Class.forName(driverClass).newInstance();
} catch (Throwable exp) {
throw new RuntimeException("Unable to load driver class: "+exp.toString(), exp);
}
log().info("Loaded JDBC driver");
// Get the JDBC url host part
InetAddress ipv4Addr = (InetAddress) iface.getAddress();
String url = null;
url = DBTools.constructUrl(ParameterMap.getKeyedString(parameters, "url", DBTools.DEFAULT_URL), ipv4Addr.getCanonicalHostName());
log().debug("JDBC url: " + url);
TimeoutTracker tracker = new TimeoutTracker(parameters, DEFAULT_RETRY, DEFAULT_TIMEOUT);
String db_user = ParameterMap.getKeyedString(parameters, "user", DBTools.DEFAULT_DATABASE_USER);
String db_pass = ParameterMap.getKeyedString(parameters, "password", DBTools.DEFAULT_DATABASE_PASSWORD);
Properties props = new Properties();
props.setProperty("user", db_user);
props.setProperty("password", db_pass);
props.setProperty("timeout", String.valueOf(tracker.getTimeoutInSeconds()));
for (tracker.reset(); tracker.shouldRetry(); tracker.nextAttempt()) {
try {
con = driver.connect(url, props);
// We are connected, upgrade the status to unresponsive
status = PollStatus.unresponsive();
if (con != null) {
log().debug("JDBC Connection Established");
tracker.startAttempt();
status = checkDatabaseStatus(con, parameters);
if (status.isAvailable()) {
double responseTime = tracker.elapsedTimeInMillis();
status = PollStatus.available(responseTime);
log().debug("JDBC service is AVAILABLE on: " + ipv4Addr.getCanonicalHostName());
log().debug("poll: responseTime= " + responseTime + "ms");
break;
}
} // end if con
} catch (SQLException sqlEx) {
status = logDown(Level.INFO, "JDBC service is not responding on: " + ipv4Addr.getCanonicalHostName() + ", " + sqlEx.getSQLState() + ", " + sqlEx.toString(), sqlEx);
} finally {
closeResultSet(resultset);
closeStmt(statement);
closeConnection(con);
}
}
return status;
}
private void closeConnection(Connection con) {
if (con == null) return;
try {
con.close();
} catch (SQLException ignore) {
}
}
/**
* <p>closeStmt</p>
*
* @param statement a {@link java.sql.Statement} object.
*/
protected void closeStmt(Statement statement) {
if (statement != null) {
try {
statement.close();
} catch (SQLException ignore) {
}
}
}
private void closeResultSet(ResultSet resultset) {
if (resultset != null) {
try {
resultset.close();
} catch (SQLException ignore) {
}
}
}
/**
* <p>checkDatabaseStatus</p>
*
* @param con a {@link java.sql.Connection} object.
* @param parameters a {@link java.util.Map} object.
* @return a {@link org.opennms.netmgt.model.PollStatus} object.
*/
public PollStatus checkDatabaseStatus( Connection con, Map<String,Object> parameters )
{
PollStatus status = PollStatus.unavailable("Unable to retrieve database catalogs");
ResultSet resultset = null;
try
{
// We are connected, upgrade the status to unresponsive
status = PollStatus.unresponsive();
DatabaseMetaData metadata = con.getMetaData();
resultset = metadata.getCatalogs();
while (resultset.next())
{
resultset.getString(1);
}
// The query worked, assume than the server is ok
if (resultset != null)
{
status = PollStatus.available();
}
}
catch (SQLException sqlEx)
{
status = logDown(Level.DEBUG, "JDBC service failed to retrieve metadata: " + sqlEx.getSQLState() + ", " + sqlEx.toString(), sqlEx);
}
finally
{
closeResultSet(resultset);
}
return status;
}
} // End of class