Download (direct link):
52 Item 5
Confusing? We have presented this graphically in Figure 5.2 for your convenience. In our earlier example tests with BadLoggerExamplel.java in Listing 5.1, everything seemed to work when we set the level to Level.INFO and Level.SEVERE, because those levels were higher than Level.INFO, the default level for the parent logger. However, when we set the level to Level.FINE, the parent's logger's handler was only passed messages higher than and equal to Level.INFO.
Luckily, it is very simple to set the levels for your handlers and loggers with the setLevel() method, and it is possible to not send messages to your logger's parent with the logger's setUseParentsHandlers(false) method. Listing 5.4 shows our changes to Listing 5.2, where we modify the constructor to set all of the handlers at the same level.
10 public GoodLoggerExample(Level l)
12 FileHandler fh = null;
13 ConsoleHandler ch = new ConsoleHandler();
15 //This creates the logger!
16 m_log = 2
18 //Try to create a FileHandler that writes it to file!
21 fh = new FileHandler("log.xml");
24 catch ( IOException ioexc )
29 /* This will set everything to the same level! */
Listing 5.4 Better constructor—GoodLoggerExample.java
In Listing 5.4, we want to create our own ConsoleHandler to log user-friendly messages to standard error, and we will continue to have our own FileHandler to write XML messages to file. On line 13, we instantiate a new ConsoleHandler, and on line 17, we add it to our logger. Finally, lines 29 to 33 fix the rest: we set the level of the logger (and every handler) to the same level, and we set our logger to not send messages to our parent's handler. The result of this program is the expected output.
When Implementations of Standard APIs Collide 53
Understanding the relationships of loggers and handlers and levels of granularity, shown in Figure 5.2, is very important. Our examples in this pitfall were created to give you an understanding of these relationships, and often, you will not want the same levels of granularity for every handler. Most of the time, logs to the console will be "user-friendly" warning messages, and log files may be debugging information for programmers and system administrators. The fact that you can create your own handlers, and set your logging levels at runtime, is very powerful. Studying this pitfall should lead to a better understanding of the java.util.logging package.
Item 6: When Implementations of Standard APIs Collide
Over the past three years, a plethora of XML processing software packages were released. First there were proprietary APIs, and then as the SAX and DOM standards evolved, vendors developed Java toolkits for developers to use. Developers began writing programs with these APIs, and as the standards evolved, you changed your code. As different toolkits used different levels of DOM compliancy, and as you integrated more software into your baseline, you had to go through your entire codebase, trying to determine which DOM API was needed for which application, and trying to determine if two modules using different levels of DOM compliancy could run together in the same application, since both used the org.w3c.dom.* classes, but some were based on different underlying implementations and different levels of DOM compliancy. If you started using one implementation of the DOM and later switched to another implementation of the DOM, sometimes your code needed to be tweaked. If you were one of the early adopters of processing XML in Java, you know our pain.
The release of JDK 1.4 brought a little complexity to the issue, because classes such as org.w3c.dom.* and org.xml.sax.* are now in the standard runtime environment, and thus read before your classpath which is chock full of your favorite XML JAR files. Because of this, if you use a later implementation of SAX or DOM than the classes in the JDK, or if you use a method that is implementation-specific, you may run into problems. A good example can be seen in Listing 6.1, ScheduleSwitcher.java. Here we simply parse an XML "schedule file," with an example schedule shown in Listing 6.2.
001 package org.javapitfalls.item6;
002 import org.w3c.dom.*;
003 import javax.xml.parsers.*;
006 * A simple class that demonstrates different functionality
007 * between DOM implementations
009 public class ScheduleSwitcher
011 /* The DOM document loaded in memory */
Listing 6.1 ScheduleSwitcher.java (continued)
54 Item 6
012 Document m_doc = null;
013 public ScheduleSwitcher(String filename)
015 /* Parse a file */
018 DocumentBuilderFactory factory =