001: /*
002: * Copyright 2002-2005 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.springframework.orm.toplink.support;
018:
019: import java.lang.reflect.Method;
020:
021: import oracle.toplink.logging.AbstractSessionLog;
022: import oracle.toplink.logging.SessionLogEntry;
023: import org.apache.commons.logging.Log;
024: import org.apache.commons.logging.LogFactory;
025:
026: /**
027: * TopLink 10.1.3+ SessionLog implementation that logs through Commons Logging.
028: *
029: * <p>The namespace used is "oracle.toplink.xxx", with the latter part being
030: * the TopLink log category ("sql"/"transaction"/etc). In case of no category
031: * given, "session" will be used as default. This allows for fine-grained
032: * filtering of log messages, for example through Log4J configuration.
033: *
034: * <p>Maps TopLink's SEVERE level to CL ERROR, TopLink's WARNING to CL WARN,
035: * TopLink's INFO to CL INFO, TopLink's CONFIG/FINE/FINER to CL DEBUG,
036: * and TopLink's FINEST to CL TRACE. This results in common CL log behavior:
037: * INFO logging only at startup; operation logging at DEBUG level. Debug logging
038: * can be further filtered according to categories: for example, activate Log4J
039: * DEBUG logging for category "oracle.toplink.sql" to see the generated SQL.
040: *
041: * <p><b>Note:</b> This implementation will only work on TopLink 10.1.3 or higher,
042: * as it is built against TopLink's new SessionLog facilities in the
043: * <code>oracle.toplink.logging</code> package, supporting log categories.
044: *
045: * @author Juergen Hoeller
046: * @since 1.2
047: * @see CommonsLoggingSessionLog904
048: * @see oracle.toplink.logging.JavaLog
049: * @see org.springframework.orm.toplink.LocalSessionFactoryBean#setSessionLog
050: */
051: public class CommonsLoggingSessionLog extends AbstractSessionLog {
052:
053: public static final String NAMESPACE_PREFIX = "oracle.toplink.";
054:
055: public static final String DEFAULT_NAMESPACE = "session";
056:
057: public static final String DEFAULT_SEPARATOR = "--";
058:
059: private static Method getExceptionMethod;
060:
061: static {
062: try {
063: getExceptionMethod = SessionLogEntry.class.getMethod(
064: "getException", new Class[0]);
065: } catch (NoSuchMethodException ex) {
066: throw new IllegalStateException(
067: "Could not find method SessionLogEntry.getException()");
068: }
069: }
070:
071: private String separator = DEFAULT_SEPARATOR;
072:
073: /**
074: * Specify the separator between TopLink's supplemental details
075: * (session, connection) and the log message itself. Default is "--".
076: */
077: public void setSeparator(String separator) {
078: this .separator = separator;
079: }
080:
081: /**
082: * Return the separator between TopLink's supplemental details
083: * (session, connection) and the log message itself. Default is "--".
084: */
085: public String getSeparator() {
086: return separator;
087: }
088:
089: public void log(SessionLogEntry entry) {
090: Log logger = LogFactory.getLog(getCategory(entry));
091: switch (entry.getLevel()) {
092: case SEVERE:
093: if (logger.isErrorEnabled()) {
094: if (entry.hasException()) {
095: logger.error(getMessageString(entry),
096: getException(entry));
097: } else {
098: logger.error(getMessageString(entry));
099: }
100: }
101: break;
102: case WARNING:
103: if (logger.isWarnEnabled()) {
104: if (entry.hasException()) {
105: logger.warn(getMessageString(entry),
106: getException(entry));
107: } else {
108: logger.warn(getMessageString(entry));
109: }
110: }
111: break;
112: case INFO:
113: if (logger.isInfoEnabled()) {
114: if (entry.hasException()) {
115: logger.info(getMessageString(entry),
116: getException(entry));
117: } else {
118: logger.info(getMessageString(entry));
119: }
120: }
121: break;
122: case CONFIG:
123: case FINE:
124: case FINER:
125: if (logger.isDebugEnabled()) {
126: if (entry.hasException()) {
127: logger.debug(getMessageString(entry),
128: getException(entry));
129: } else {
130: logger.debug(getMessageString(entry));
131: }
132: }
133: break;
134: case FINEST:
135: if (logger.isTraceEnabled()) {
136: if (entry.hasException()) {
137: logger.trace(getMessageString(entry),
138: getException(entry));
139: } else {
140: logger.trace(getMessageString(entry));
141: }
142: }
143: break;
144: }
145: }
146:
147: /**
148: * Determine the log category for the given log entry.
149: * <p>If the entry carries a name space value, it will be appended
150: * to the "oracle.toplink." prefix; else, "oracle.toplink.session"
151: * will be used.
152: */
153: protected String getCategory(SessionLogEntry entry) {
154: if (entry.getNameSpace() != null) {
155: return NAMESPACE_PREFIX + entry.getNameSpace();
156: }
157: return NAMESPACE_PREFIX + DEFAULT_NAMESPACE;
158: }
159:
160: /**
161: * Build the message String for the given log entry, including the
162: * supplemental details (session, connection) and the formatted message.
163: * @see #getSessionString(oracle.toplink.sessions.Session)
164: * @see #getConnectionString(oracle.toplink.internal.databaseaccess.Accessor)
165: * @see #formatMessage(oracle.toplink.logging.SessionLogEntry)
166: * @see #getSeparator()
167: */
168: protected String getMessageString(SessionLogEntry entry) {
169: StringBuffer buf = new StringBuffer();
170: if (entry.getSession() != null) {
171: buf.append(getSessionString(entry.getSession()));
172: buf.append(getSeparator());
173: }
174: if (entry.getConnection() != null) {
175: buf.append(getConnectionString(entry.getConnection()));
176: buf.append(getSeparator());
177: }
178: buf.append(formatMessage(entry));
179: return buf.toString();
180: }
181:
182: /**
183: * Extract the exception from the given log entry.
184: * <p>Default implementations calls <code>SessionLogEntry.getException</code>
185: * via reflection: The return type varies between TopLink 9.0.4 and 10.1.3
186: * (<code>Exception</code> vs <code>Throwable</code>, respectively),
187: * which does not allow us to compile both CommonsLoggingSessionLog904 and
188: * CommonsLoggingSessionLog against the same <code>getException</code> method.
189: */
190: protected Throwable getException(SessionLogEntry entry) {
191: try {
192: return (Throwable) getExceptionMethod.invoke(entry,
193: new Object[0]);
194: } catch (Exception ex) {
195: throw new IllegalStateException(
196: "Could not invoke method SessionLogEntry.getException(): "
197: + ex.getMessage());
198: }
199: }
200:
201: /**
202: * Throws an UnsupportedOperationException: This method is not
203: * called any longer as of TopLink 10.1.3, but abstract in
204: * 10.1.3 Preview 3 (which we want to be able to compile against).
205: * <p>Do not remove this method for the time being, even if the
206: * superclass method is no longer abstract in <code>toplink-api.jar</code>!
207: */
208: public void log(oracle.toplink.sessions.SessionLogEntry entry) {
209: throw new UnsupportedOperationException(
210: "oracle.toplink.sessions.SessionLogEntry not supported");
211: }
212:
213: }
|