/** * NOTE: This copyright does *not* cover user programs that use HQ * program services by normal system calls through the application * program interfaces provided as part of the Hyperic Plug-in Development * Kit or the Hyperic Client Development Kit - this is merely considered * normal use of the program, and does *not* fall under the heading of * "derived work". * * Copyright (C) [2009-2010], VMware, Inc. * This file is part of HQ. * * HQ is free software; you can redistribute it and/or modify * it under the terms version 2 of the GNU General Public License as * published by the Free Software Foundation. This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA. * */ /* * To change this template, choose Tools | Templates * and open the template in the editor. */ package org.hyperic.hq.plugin.db2jdbc; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.HashMap; import java.util.Hashtable; import java.util.Map; import org.hyperic.hq.product.JDBCMeasurementPlugin; import org.hyperic.hq.product.Metric; import org.hyperic.hq.product.MetricNotFoundException; import org.hyperic.hq.product.MetricUnreachableException; import org.hyperic.hq.product.MetricValue; import org.hyperic.util.jdbc.DBUtil; /** * * @author laullon */ public abstract class CachedJDBCMeasurement extends JDBCMeasurementPlugin { private static final String EXEC_TIME_ATTR = "QueryExecTime"; private static final Hashtable cache = new Hashtable(); protected void initQueries() { } protected String getDefaultURL() { return ""; } public MetricValue getValue(Metric metric) throws MetricUnreachableException, MetricNotFoundException { Map values; String key = getCacheKey(metric); CacheEntry ce = (CacheEntry) cache.get(key); if (!isCacheEntryValid(ce, metric)) { try { values = executeQuery(metric); cache.put(key, new CacheEntry(values)); } catch (MetricNotFoundException ex) { if (getLog().isDebugEnabled()) { getLog().error("Metric: '" + metric + "' Error='" + ex.getMessage() + "'", ex); } throw ex; } } else { values = (Map) ce.getEntry(); } MetricValue res = (MetricValue) values.get(metric.getAttributeName()); if (res == null) { throw new MetricNotFoundException(metric.getAttributeName() + " => NULL"); } return res; } protected final Map executeQuery(Metric metric) throws MetricNotFoundException { Map res = new HashMap(); res.put(AVAIL_ATTR, new MetricValue(Metric.AVAIL_DOWN)); String query = getQuery(metric); if (query == null) { throw new IllegalArgumentException("No SQL query"); } getLog().debug("[executeQuery] query='" + query + "'"); String url = metric.getProperties().getProperty(PROP_URL); String user = metric.getProperties().getProperty(PROP_USER); String pass = metric.getProperties().getProperty(PROP_PASSWORD); Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; PreparedStatement tps = null; try { conn = getCachedConnection(url, user, pass); tps = conn.prepareStatement("select 1 from sysibm.sysdummy1"); tps.execute(); getLog().debug("** cn - " + url + user + pass + " - " + conn); } catch (SQLException e) { PreparedStatement tps2 = null; try { getLog().debug("conection closed '" + e.getMessage() + "'... reconectinig (" + url + ")"); removeCachedConnection(url, user, pass); conn = getCachedConnection(url, user, pass); tps2 = conn.prepareStatement("select 1 from sysibm.sysdummy1"); tps2.execute(); } catch (SQLException ex) { removeCachedConnection(url, user, pass); throw new MetricNotFoundException(ex.getMessage()); } finally { if (tps2 != null) { try { tps2.close(); } catch (SQLException ex) { removeCachedConnection(url, user, pass); throw new MetricNotFoundException(ex.getMessage()); } } } } finally { if (tps != null) { try { tps.close(); } catch (SQLException ex) { removeCachedConnection(url, user, pass); throw new MetricNotFoundException(ex.getMessage()); } } } try { ps = conn.prepareStatement(query); long startTime = System.currentTimeMillis(); rs = ps.executeQuery(); long totalTime = System.currentTimeMillis() - startTime; res.put(EXEC_TIME_ATTR, new MetricValue(totalTime)); res.put(AVAIL_ATTR, new MetricValue(Metric.AVAIL_UP)); if (getLog().isTraceEnabled()) { getLog().trace("key='" + AVAIL_ATTR + "'\tvalue='" + res.get(AVAIL_ATTR) + "'(" + res.get(AVAIL_ATTR).getClass() + ")"); } res.putAll(processResulSet(rs, metric)); } catch (SQLException ex) { getLog().error("Error fetching metrics", ex); removeCachedConnection(url, user, pass); throw new MetricNotFoundException(ex.getMessage()); } finally { DBUtil.closeJDBCObjects(getLog(), null, ps, rs); } return res; } abstract Map processResulSet( ResultSet rs, Metric metric) throws MetricNotFoundException; private String getCacheKey( Metric metric) { return getQuery(metric) + metric.getProperties().toString(); } private boolean isCacheEntryValid(CacheEntry ce, Metric metric) { long now = System.currentTimeMillis() / 1000; if (getLog().isDebugEnabled()) { getLog().debug("-->getValue(" + metric + ")"); if (ce == null) { getLog().debug("== ce==null"); } else if (metric.getAttributeName().equals(AVAIL_ATTR)) { getLog().debug("== AVAIL_ATTR"); } else if (metric.getAttributeName().equals(EXEC_TIME_ATTR)) { getLog().debug("== EXEC_TIME_ATTR"); } else if ((now - ce.getTime()) > 60) { getLog().debug("== time='" + (now - ce.getTime()) + "'"); } } boolean invalid = (ce == null) || ((now - ce.getTime()) > 60) || metric.getAttributeName().endsWith(AVAIL_ATTR) || metric.getAttributeName().equals(EXEC_TIME_ATTR); if (getLog().isDebugEnabled()) { if (invalid) { getLog().debug("*** NO CACHE ***"); } else { getLog().debug("*** CACHE HIT ***"); } } return !invalid; } private final class CacheEntry { private long time; private Object entry; public CacheEntry(Object entry) { this.entry = entry; time = System.currentTimeMillis() / 1000; } public Object getEntry() { return entry; } public long getTime() { return time; } } }