001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2006, Geotools Project Managment Committee (PMC)
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2.1 of the License, or (at your option) any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: */
016: package org.geotools.util;
017:
018: // J2SE dependencies
019: import java.util.logging.Level;
020: import java.util.logging.Logger;
021: import java.util.logging.LogRecord;
022: import java.util.logging.Handler; // For javadoc
023: import java.util.logging.ConsoleHandler; // For javadoc
024: import java.util.logging.SimpleFormatter; // For javadoc
025:
026: // Geotools dependencies
027: import org.geotools.resources.Utilities;
028:
029: /**
030: * A set of utilities method for configuring loggings in Geotools. Those methods operates on the
031: * {@linkplain java.util.logging Java logging framework}, which is the framework used by Geotools.
032: *
033: * @since 2.4
034: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/metadata/src/main/java/org/geotools/util/Logging.java $
035: * @version $Id: Logging.java 27874 2007-11-13 14:23:34Z aaime $
036: * @author Martin Desruisseaux
037: *
038: * @deprecated Moved to the {@link org.geotools.util.logging} package.
039: */
040: public final class Logging {
041: /**
042: * Logging configuration that applies only to Geotools packages.
043: */
044: public static final Logging GEOTOOLS = new Logging("org.geotools");
045:
046: /**
047: * Logging configuration that applied to all packages.
048: */
049: public static final Logging ALL = new Logging("");
050:
051: /**
052: * The root package.
053: */
054: private final String root;
055:
056: /**
057: * {@code true} if {@link #redirectToCommonsLogging} has been invoked.
058: */
059: private boolean redirected;
060:
061: /**
062: * Creates an instance for the specified root package.
063: */
064: public Logging(final String root) {
065: this .root = root;
066: }
067:
068: /**
069: * Configures the default {@linkplain ConsoleHandler console handler} in order to log records
070: * on a single line instead of two lines. More specifically, for each {@link ConsoleHandler}
071: * using a {@link SimpleFormatter}, this method replaces the simple formatter by an instance
072: * of {@link MonolineFormatter}. If no {@link ConsoleHandler} are found, then a new one is
073: * created.
074: * <p>
075: * Note that {@link MonolineFormatter} writes to the {@linkplain System#out standard
076: * output stream} instead of the {@linkplain System#err standard error stream}.
077: *
078: * @throws IllegalStateException is {@link #redirectToCommonsLogging} has been invoked.
079: */
080: public void forceMonolineConsoleOutput()
081: throws IllegalStateException {
082: forceMonolineConsoleOutput(null);
083: }
084:
085: /**
086: * Same as {@link #forceMonolineConsoleOutput()}, but additionnaly set an optional logging
087: * level. If the specified level is non-null, then all {@link Handler}s using the monoline
088: * formatter will be set to the specified level.
089: * <p>
090: * <b>Note:</b> Avoid this method as much as possible, since it overrides user's level
091: * setting. A user trying to configure his logging properties may find confusing to see
092: * his setting ignored.
093: *
094: * @throws IllegalStateException is {@link #redirectToCommonsLogging} has been invoked.
095: *
096: * @see org.geotools.factory.GeoTools#init
097: */
098: public synchronized void forceMonolineConsoleOutput(
099: final Level level) throws IllegalStateException {
100: if (redirected) {
101: throw new IllegalStateException();
102: }
103: final MonolineFormatter f = MonolineFormatter.init(root, level);
104: // As of new MonolineFormatter.init(...) specification, 'f' should never be null.
105: if (f.getSourceFormat() == null) {
106: // Set the source format only if the user didn't specified
107: // an explicit one in the jre/lib/logging.properties file.
108: f.setSourceFormat("class:short");
109: }
110: }
111:
112: /**
113: * Redirects {@linkplain java.util.logging Java logging} events to the Apache's
114: * <A HREF="http://jakarta.apache.org/commons/logging/">commons-logging</A> framework.
115: * <p>
116: * This method should be invoked again when the common-logging configuration change. For
117: * example if the <cite>Log4J</cite> configuration is dynamically changed at runtime, then
118: * this method should be invoked again.
119: * <p>
120: * If this method determines that commons-logging would redirect all log events
121: * to the java logging system, then this method do nothing and return {@code false}.
122: *
123: * @return {@code true} if the adapter has been installed or re-installed, or
124: * {@code false} if this method did nothing.
125: *
126: * @see org.geotools.factory.GeoTools#init
127: *
128: * @deprecated Replaced by {@link org.geotools.util.logging.Logging#setLoggerFactory}.
129: */
130: public synchronized boolean redirectToCommonsLogging() {
131: try {
132: if (CommonHandler.install(root)) {
133: assert isCommonsLoggingAvailable();
134: redirected = true;
135: return true;
136: }
137: } catch (NoClassDefFoundError error) {
138: // May occurs if commons-logging is not in the classpath.
139: Utilities.recoverableException("org.geotools.util",
140: Logging.class, "redirectToCommonsLogging", error);
141: }
142: return false;
143: }
144:
145: /**
146: * Returns {@code true} if the
147: * <A HREF="http://jakarta.apache.org/commons/logging/">commons-logging</A>
148: * framework seems to be available on the classpath.
149: *
150: * @deprecated Just try to set the commons logger factory, an exception will occurr if
151: * commons logging is not available
152: */
153: public static boolean isCommonsLoggingAvailable() {
154: try {
155: Class.forName("org.apache.commons.logging.Log", false,
156: Logging.class.getClassLoader());
157: return true;
158: } catch (ClassNotFoundException e) {
159: return false;
160: }
161: }
162:
163: /**
164: * Invoked when an unexpected error occurs. This method logs a message at the
165: * {@link Level#WARNING WARNING} level to the specified logger. The originating
166: * class name and method name are inferred from the error stack trace, using the
167: * first {@linkplain StackTraceElement stack trace element} for which the class
168: * name is inside a package or sub-package of the logger name. For example if
169: * the logger name is {@code "org.geotools.image"}, then this method will uses
170: * the first stack trace element where the fully qualified class name starts with
171: * {@code "org.geotools.image"} or {@code "org.geotools.image.io"}, but not
172: * {@code "org.geotools.imageio"}.
173: *
174: * @param logger Where to log the error.
175: * @param error The error that occured.
176: * @return {@code true} if the error has been logged, or {@code false} if the logger
177: * doesn't log anything at the {@link Level#WARNING WARNING} level.
178: */
179: public static boolean unexpectedException(final Logger logger,
180: final Throwable error) {
181: if (logger.isLoggable(Level.WARNING)) {
182: unexpectedException(logger.getName(), (String) null, null,
183: error);
184: return true;
185: }
186: return false;
187: }
188:
189: /**
190: * Invoked when an unexpected error occurs. This method logs a message at the
191: * {@link Level#WARNING WARNING} level to the specified logger. The originating
192: * class name and method name can optionnaly be specified. If any of them is
193: * {@code null}, then it will be inferred from the error stack trace as in
194: * {@link #unexpectedException(Logger, Throwable)}.
195: * <p>
196: * Explicit value for class and method names are sometime preferred to automatic
197: * inference for the following reasons:
198: *
199: * <ul>
200: * <li><p>Automatic inference is not 100% reliable, since the Java Virtual Machine
201: * is free to omit stack frame in optimized code.</p></li>
202: * <li><p>When an exception occured in a private method used internally by a public
203: * method, we sometime want to log the warning for the public method instead,
204: * since the user is not expected to know anything about the existence of the
205: * private method. If a developper really want to know about the private method,
206: * the stack trace is still available anyway.</p></li>
207: * </ul>
208: *
209: * @param logger Where to log the error.
210: * @param classe The class where the error occurred, or {@code null}.
211: * @param method The method where the error occurred, or {@code null}.
212: * @param error The error.
213: */
214: public static void unexpectedException(final Logger logger,
215: final Class classe, final String method,
216: final Throwable error) {
217: // TODO: Refactor in order to use directly the logger after we removed the deprecated method.
218: unexpectedException(logger.getName(), classe, method, error);
219: }
220:
221: /**
222: * Invoked when an unexpected error occurs. This method logs a message at the
223: * {@link Level#WARNING WARNING} level to the logger for the specified package
224: * name. The originating class name and method name can optionnaly be specified.
225: * If any of them is {@code null}, then it will be inferred from the error stack
226: * trace as in {@link #unexpectedException(Logger, Throwable)}.
227: *
228: * @param paquet The package where the error occurred, or {@code null}. This
229: * information is used for fetching an appropriate {@link Logger}
230: * for logging the error.
231: * @param classe The class where the error occurred, or {@code null}.
232: * @param method The method where the error occurred, or {@code null}.
233: * @param error The error.
234: */
235: public static void unexpectedException(final String paquet,
236: final Class classe, final String method,
237: final Throwable error) {
238: // TODO: use getSimpleName() or getCanonicalName() when we will be allowed to target J2SE 1.5.
239: unexpectedException(paquet, (classe != null) ? classe.getName()
240: : (String) null, method, error);
241: }
242:
243: /**
244: * Same as {@link #unexpectedException(String, Class, String, Throwable)
245: * unexpectedException(..., Class, ...)} except that the class name is
246: * specified as a string.
247: *
248: * @param paquet The package where the error occurred, or {@code null}. This
249: * information is used for fetching an appropriate {@link Logger}
250: * for logging the error.
251: * @param classe The class where the error occurred, or {@code null}.
252: * @param method The method where the error occurred, or {@code null}.
253: * @param error The error.
254: *
255: * @deprecated Use {@link #unexpectedException(String, Class, String, Throwable)}
256: * instead, for type safety.
257: */
258: public static void unexpectedException(String paquet,
259: String classe, String method, final Throwable error) {
260: final LogRecord record = Utilities.getLogRecord(error);
261: if (paquet == null || classe == null || method == null) {
262: final StackTraceElement[] elements = error.getStackTrace();
263: for (int i = 0; i < elements.length; i++) {
264: final StackTraceElement e = elements[i];
265: final String c = e.getClassName();
266: if (paquet != null) {
267: if (!c.startsWith(paquet)) {
268: continue;
269: }
270: final int lg = paquet.length();
271: if (c.length() > lg
272: && Character.isJavaIdentifierPart(c
273: .charAt(lg))) {
274: continue;
275: }
276: }
277: if (classe != null) {
278: if (!c.endsWith(classe)) {
279: continue;
280: }
281: final int lg = c.length() - classe.length() - 1;
282: if (c.length() >= 0
283: && Character.isJavaIdentifierPart(c
284: .charAt(lg))) {
285: continue;
286: }
287: }
288: final String m = e.getMethodName();
289: if (method != null) {
290: if (!m.equals(method)) {
291: continue;
292: }
293: }
294: final int separator = c.lastIndexOf('.');
295: if (paquet == null) {
296: paquet = (separator >= 1) ? c.substring(0,
297: separator - 1) : "";
298: }
299: if (classe == null) {
300: classe = c.substring(separator + 1);
301: }
302: if (method == null) {
303: method = m;
304: }
305: break;
306: }
307: }
308: record.setSourceClassName(classe);
309: record.setSourceMethodName(method);
310: record.setThrown(error);
311: Logger.getLogger(paquet).log(record);
312: }
313: }
|