/* * Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Florent Guillaume */ package org.eclipse.ecr.core.storage.sql.jdbc; import java.io.Serializable; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.eclipse.ecr.core.storage.sql.Binary; import org.eclipse.ecr.core.storage.sql.Row; import org.eclipse.ecr.core.storage.sql.jdbc.db.Column; import org.nuxeo.common.utils.StringUtils; /** * Logger used for debugging. */ public class JDBCLogger { public static final Log log = LogFactory.getLog(JDBCLogger.class); public static final int DEBUG_MAX_STRING = 100; public static final int DEBUG_MAX_ARRAY = 10; public final String instance; public JDBCLogger(String instance) { this.instance = instance; } public boolean isLogEnabled() { return log.isTraceEnabled(); } public String formatMessage(String message) { return "(" + instance + ") SQL: " + message; } public void error(String message) { log.error(formatMessage(message)); } public void error(String message, Throwable t) { log.error(formatMessage(message), t); } public void warn(String message) { log.warn(formatMessage(message)); } public void info(String message) { log.info(formatMessage(message)); } public void log(String message) { log.trace(formatMessage(message)); } public void logCount(int count) { if (count > 0 && isLogEnabled()) { log(" -> " + count + " row" + (count > 1 ? "s" : "")); } } public void logResultSet(ResultSet rs, List<Column> columns) throws SQLException { List<String> res = new LinkedList<String>(); int i = 0; for (Column column : columns) { i++; Serializable v = column.getFromResultSet(rs, i); res.add(column.getKey() + "=" + loggedValue(v)); } log(" -> " + StringUtils.join(res, ", ")); } public void logMap(Map<String, Serializable> map) throws SQLException { List<String> res = new LinkedList<String>(); for (Entry<String, Serializable> en : map.entrySet()) { res.add(en.getKey() + "=" + loggedValue(en.getValue())); } log(" -> " + StringUtils.join(res, ", ")); } public void logIds(List<Serializable> ids, boolean countTotal, long totalSize) { List<Serializable> debugIds = ids; String end = ""; if (ids.size() > DEBUG_MAX_ARRAY) { debugIds = new ArrayList<Serializable>(DEBUG_MAX_ARRAY); int i = 0; for (Serializable id : ids) { debugIds.add(id); i++; if (i == DEBUG_MAX_ARRAY) { break; } } end = "...(" + ids.size() + " ids)..."; } if (countTotal) { end += " (total " + totalSize + ')'; } log(" -> " + debugIds + end); } public void logSQL(String sql, List<Column> columns, Row row) { List<Serializable> values = new ArrayList<Serializable>(columns.size()); for (Column column : columns) { values.add(row.get(column.getKey())); } logSQL(sql, values); } public void logSQL(String sql, Collection<Serializable> values) { StringBuilder buf = new StringBuilder(); int start = 0; for (Serializable v : values) { int index = sql.indexOf('?', start); if (index == -1) { // mismatch between number of ? and number of values break; } buf.append(sql, start, index); buf.append(loggedValue(v)); start = index + 1; } buf.append(sql, start, sql.length()); log(buf.toString()); } /** * Returns a loggable value using pseudo-SQL syntax. */ @SuppressWarnings("boxing") public static String loggedValue(Serializable value) { if (value == null) { return "NULL"; } if (value instanceof String) { String v = (String) value; if (v.length() > DEBUG_MAX_STRING) { v = v.substring(0, DEBUG_MAX_STRING) + "...(" + v.length() + " chars)..."; } return "'" + v.replace("'", "''") + "'"; } if (value instanceof Calendar) { Calendar cal = (Calendar) value; char sign; int offset = cal.getTimeZone().getOffset(cal.getTimeInMillis()) / 60000; if (offset < 0) { offset = -offset; sign = '-'; } else { sign = '+'; } return String.format( "TIMESTAMP '%04d-%02d-%02dT%02d:%02d:%02d.%03d%c%02d:%02d'", cal.get(Calendar.YEAR), // cal.get(Calendar.MONTH) + 1, // cal.get(Calendar.DAY_OF_MONTH), // cal.get(Calendar.HOUR_OF_DAY), // cal.get(Calendar.MINUTE), // cal.get(Calendar.SECOND), // cal.get(Calendar.MILLISECOND), // sign, offset / 60, offset % 60); } if (value instanceof Binary) { return "'" + ((Binary) value).getDigest() + "'"; } if (value.getClass().isArray()) { Serializable[] v = (Serializable[]) value; StringBuilder b = new StringBuilder(); b.append('['); for (int i = 0; i < v.length; i++) { if (i > 0) { b.append(','); if (i > DEBUG_MAX_ARRAY) { b.append("...(" + v.length + " items)..."); break; } } b.append(loggedValue(v[i])); } b.append(']'); return b.toString(); } return value.toString(); } }