/**
* Helios, OpenSource Monitoring
* Brought to you by the Helios Development Group
*
* Copyright 2007, Helios Development Group and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*
*/
package org.helios.collector.jdbc.extract;
import gnu.trove.map.hash.TIntObjectHashMap;
import org.helios.apmrouter.jmx.XMLHelper;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.sql.*;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
/**
* <p>Title: ResultSetExtractorImpl</p>
* <p>Description: Extracts a result set into a {@link ProcessedResultSet}</p>
* <p>Company: Helios Development Group LLC</p>
* @author Whitehead (nwhitehead AT heliosdev DOT org)
* <p><code>org.helios.collectors.jdbc.extract.ResultSetExtractorImpl</code></p>
*/
public class ResultSetExtractorImpl implements IResultSetExtractor {
/**
* Creates a map of the name/values from a result set.
* @param rset The result set to convert.
* @param maxRows The maximum number of rows to read. < 1 means all rows.
* @param useStrings If true, retrieves values as strings. If false, retrieves values according to the JDBC type code.
* @return A map of name/values for the result set keyed as follows:<code>Map<ROWID, MAP<COLID, VALUE>></code>
* @throws SQLException
* @throws IOException
*/
public Map<Integer, Map<Integer, Object>> processResultSet(ResultSet rset, int maxRows, boolean useStrings) throws SQLException, IOException {
Map<Integer, Map<Integer, Object>> prset = new TreeMap<Integer, Map<Integer, Object>>();
ResultSetMetaData rsmd = rset.getMetaData();
int columnCount = rsmd.getColumnCount();
int rowCount = 0;
while(rset.next()) {
Map<Integer, Object> row = new HashMap<Integer, Object>(columnCount);
for(int i = 1; i <= columnCount; i++) {
Object val = useStrings ? getStringValue(i, rset) : getValue(i, rsmd.getColumnType(i), rset);
row.put(i-1, val);
}
prset.put(rowCount, row);
rowCount++;
if(rowCount==maxRows) break;
}
return prset;
}
/**
* Creates a map of the name/values from a result set.
* @param rset The result set to convert.
* @param maxRows The maximum number of rows to read. < 1 means all rows.
* @param useStrings If true, retrieves values as strings. If false, retrieves values according to the JDBC type code.
* @return A map of name/values for the result set keyed as follows:<code>Map<ROWID, MAP<COLID, VALUE>></code>
* @throws SQLException
* @throws IOException
*/
public TIntObjectHashMap<TIntObjectHashMap<Object>> processResultSetX(ResultSet rset, int maxRows) throws SQLException, IOException {
TIntObjectHashMap<TIntObjectHashMap<Object>> results = null;
return results;
}
/**
* Retrieves a String value from the rset column, checking for null.
* @param index
* @param rset
* @return
* @throws SQLException
*/
protected Object getStringValue(int index, ResultSet rset) throws SQLException {
String s = rset.getString(index);
if(rset.wasNull()) s = null;
return s;
}
/**
* Creates a map of the name/values from a result set. Defaults to all rows (no maxrows) and strings for value retrieval.
* @param rset The result set to convert.
* @return A map of name/values for the result set keyed as follows:<code>Map<ROWID, MAP<COLID, VALUE>></code>
* @throws SQLException
* @throws IOException
*/
public Map<Integer, Map<Integer, Object>> processResultSet(ResultSet rset) throws SQLException, IOException {
return processResultSet(rset, -1, true);
}
/**
* Extracts the correctly typed object from the indexed result set row.
* @param columnIndex The index of the column in the current result set row.
* @param type The <code>java.sql.Types</code> type code of the column in the current row.
* @param rset The result set to extract the value from.
* @return The typed extracted object.
* @throws SQLException
* @throws IOException
*/
public Object getValue(int columnIndex, int type, ResultSet rset) throws SQLException, IOException {
Object obj = null;
switch (type) {
case -7: //BIT
obj = rset.getByte(columnIndex);
break;
case -6: //TINYINT
case 5: //SMALLINT
obj = rset.getShort(columnIndex);
break;
case 4: //INTEGER
obj = rset.getInt(columnIndex);
break;
case 6: //FLOAT
case 7: //REAL
obj = rset.getFloat(columnIndex);
break;
case 8: //DOUBLE
obj = rset.getDouble(columnIndex);
case 2: //NUMERIC
case 3: //DECIMAL
case -5: //BIGINT
obj = rset.getLong(columnIndex);
break;
case 91: //DATE
case 93: //TIMESTAMP
case 92: //TIME
obj = new Date(rset.getDate(columnIndex).getTime());
break;
case -2: //BINARY
case -3: //VARBINARY
case -4: //LONGVARBINARY
obj = rset.getBytes(columnIndex);
break;
case 0: //NULL
obj = null;
break;
case 2000: //JAVA_OBJECT
case 2001: //DISTINCT
case 2002: //STRUCT
case 2003: //ARRAY
obj = rset.getObject(columnIndex);
break;
case 2004: //BLOB
Blob blob = rset.getBlob(columnIndex);
long blength = blob.length();
int baosLength = (blength > Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int)blength;
ByteArrayOutputStream baos = new ByteArrayOutputStream(baosLength);
InputStream is = blob.getBinaryStream();
byte[] buffer = new byte[8096];
int bytesRead = 0;
while((bytesRead = is.read(buffer))!=-1) {
baos.write(buffer, 0, bytesRead);
}
obj = baos.toByteArray();
break;
case 2005: //CLOB
case 2011: //NCLOB
Clob clob = rset.getClob(columnIndex);
long clength = clob.length();
int sbLength = (clength > Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int)clength;
ByteArrayOutputStream caos = new ByteArrayOutputStream(sbLength);
InputStream cis = clob.getAsciiStream();
byte[] cbuffer = new byte[8096];
int cbytesRead = 0;
while((cbytesRead = cis.read(cbuffer))!=-1) {
caos.write(cbuffer, 0, cbytesRead);
}
obj = caos.toString();
break;
case 2006: //REF
break;
case 70: //DATALINK
break;
case 16: //BOOLEAN
obj = rset.getBoolean(columnIndex);
break;
case -8: //ROWID
obj = rset.getRowId(columnIndex);
break;
case -15: //NCHAR
case -9: //NVARCHAR
case -16: //LONGNVARCHAR
Reader reader = rset.getNCharacterStream(columnIndex);
StringBuilder b = new StringBuilder();
char[] ncbuffer = new char[1024];
int charsRead = -1;
while((charsRead = reader.read(ncbuffer))!=-1) {
b.append(ncbuffer, 0, charsRead);
}
obj = b.toString();
break;
case 2009: //SQLXML
SQLXML sqlXml = null;
try {
sqlXml = rset.getSQLXML(columnIndex);
obj = XMLHelper.parseXML(sqlXml.getString()).getDocumentElement();
} finally {
if(sqlXml!=null) try { sqlXml.free(); } catch (Exception e) {}
}
break;
case 1: //CHAR
case 12: //VARCHAR
case -1: //LONGVARCHAR
case 1111: //OTHER
default: // EVERYTHING ELSE
obj = rset.getString(columnIndex);
break;
}
if(rset.wasNull()) obj = null;
return obj;
}
}