DOMTreeTest.java Source code

Java tutorial

Introduction

Here is the source code for DOMTreeTest.java

Source

    /*
       This program is a part of the companion code for Core Java 8th ed.
       (http://horstmann.com/corejava)
    
       This program is free software: you can redistribute it and/or modify
       it under the terms of the GNU General Public License as published by
       the Free Software Foundation, either version 3 of the License, or
       (at your option) any later version.
    
       This program 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 General Public License for more details.
    
       You should have received a copy of the GNU General Public License
       along with this program.  If not, see <http://www.gnu.org/licenses/>.
    */

    import java.awt.*;
    import java.awt.event.*;
    import java.io.*;
    import javax.swing.*;
    import javax.swing.event.*;
    import javax.swing.table.*;
    import javax.swing.tree.*;
    import javax.xml.parsers.*;
    import org.w3c.dom.*;

    /**
     * This program displays an XML document as a tree.
     * @version 1.11 2007-06-24
     * @author Cay Horstmann
     */
    public class DOMTreeTest {
        public static void main(String[] args) {
            EventQueue.invokeLater(new Runnable() {
                public void run() {
                    JFrame frame = new DOMTreeFrame();
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.setVisible(true);
                }
            });
        }
    }

    /**
     * This frame contains a tree that displays the contents of an XML document.
     */
    class DOMTreeFrame extends JFrame {
        public DOMTreeFrame() {
            setTitle("DOMTreeTest");
            setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);

            JMenu fileMenu = new JMenu("File");
            JMenuItem openItem = new JMenuItem("Open");
            openItem.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent event) {
                    openFile();
                }
            });
            fileMenu.add(openItem);

            JMenuItem exitItem = new JMenuItem("Exit");
            exitItem.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent event) {
                    System.exit(0);
                }
            });
            fileMenu.add(exitItem);

            JMenuBar menuBar = new JMenuBar();
            menuBar.add(fileMenu);
            setJMenuBar(menuBar);
        }

        /**
         * Open a file and load the document.
         */
        public void openFile() {
            JFileChooser chooser = new JFileChooser();
            chooser.setCurrentDirectory(new File("."));

            chooser.setFileFilter(new javax.swing.filechooser.FileFilter() {
                public boolean accept(File f) {
                    return f.isDirectory() || f.getName().toLowerCase().endsWith(".xml");
                }

                public String getDescription() {
                    return "XML files";
                }
            });
            int r = chooser.showOpenDialog(this);
            if (r != JFileChooser.APPROVE_OPTION)
                return;
            final File file = chooser.getSelectedFile();

            new SwingWorker<Document, Void>() {
                protected Document doInBackground() throws Exception {
                    if (builder == null) {
                        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
                        builder = factory.newDocumentBuilder();
                    }
                    return builder.parse(file);
                }

                protected void done() {
                    try {
                        Document doc = get();
                        JTree tree = new JTree(new DOMTreeModel(doc));
                        tree.setCellRenderer(new DOMTreeCellRenderer());

                        setContentPane(new JScrollPane(tree));
                        validate();
                    } catch (Exception e) {
                        JOptionPane.showMessageDialog(DOMTreeFrame.this, e);
                    }
                }
            }.execute();
        }

        private DocumentBuilder builder;
        private static final int DEFAULT_WIDTH = 400;
        private static final int DEFAULT_HEIGHT = 400;
    }

    /**
     * This tree model describes the tree structure of an XML document.
     */
    class DOMTreeModel implements TreeModel {
        /**
         * Constructs a document tree model.
         * @param doc the document
         */
        public DOMTreeModel(Document doc) {
            this.doc = doc;
        }

        public Object getRoot() {
            return doc.getDocumentElement();
        }

        public int getChildCount(Object parent) {
            Node node = (Node) parent;
            NodeList list = node.getChildNodes();
            return list.getLength();
        }

        public Object getChild(Object parent, int index) {
            Node node = (Node) parent;
            NodeList list = node.getChildNodes();
            return list.item(index);
        }

        public int getIndexOfChild(Object parent, Object child) {
            Node node = (Node) parent;
            NodeList list = node.getChildNodes();
            for (int i = 0; i < list.getLength(); i++)
                if (getChild(node, i) == child)
                    return i;
            return -1;
        }

        public boolean isLeaf(Object node) {
            return getChildCount(node) == 0;
        }

        public void valueForPathChanged(TreePath path, Object newValue) {
        }

        public void addTreeModelListener(TreeModelListener l) {
        }

        public void removeTreeModelListener(TreeModelListener l) {
        }

        private Document doc;
    }

    /**
     * This class renders an XML node.
     */
    class DOMTreeCellRenderer extends DefaultTreeCellRenderer {
        public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded,
                boolean leaf, int row, boolean hasFocus) {
            Node node = (Node) value;
            if (node instanceof Element)
                return elementPanel((Element) node);

            super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
            if (node instanceof CharacterData)
                setText(characterString((CharacterData) node));
            else
                setText(node.getClass() + ": " + node.toString());
            return this;
        }

        public static JPanel elementPanel(Element e) {
            JPanel panel = new JPanel();
            panel.add(new JLabel("Element: " + e.getTagName()));
            final NamedNodeMap map = e.getAttributes();
            panel.add(new JTable(new AbstractTableModel() {
                public int getRowCount() {
                    return map.getLength();
                }

                public int getColumnCount() {
                    return 2;
                }

                public Object getValueAt(int r, int c) {
                    return c == 0 ? map.item(r).getNodeName() : map.item(r).getNodeValue();
                }
            }));
            return panel;
        }

        public static String characterString(CharacterData node) {
            StringBuilder builder = new StringBuilder(node.getData());
            for (int i = 0; i < builder.length(); i++) {
                if (builder.charAt(i) == '\r') {
                    builder.replace(i, i + 1, "\\r");
                    i++;
                } else if (builder.charAt(i) == '\n') {
                    builder.replace(i, i + 1, "\\n");
                    i++;
                } else if (builder.charAt(i) == '\t') {
                    builder.replace(i, i + 1, "\\t");
                    i++;
                }
            }
            if (node instanceof CDATASection)
                builder.insert(0, "CDATASection: ");
            else if (node instanceof Text)
                builder.insert(0, "Text: ");
            else if (node instanceof Comment)
                builder.insert(0, "Comment: ");

            return builder.toString();
        }
    }

    <?xml version="1.0"encoding="ISO-8859-1"?>

    <Server><!--
    Debug low-level events
    in XmlMapper startup<xmlmapper:debug level="0" />
    -->
    
    <!-- 

    Logging:

    Logging in
    Tomcat is
    quite flexible;
    we can
    either have
    a log
    file per

    module (example: ContextManager) or we can have one
         for Servlets and one for Jasper, or we can just have one
         tomcat.log for both Servlet and Jasper.  Right now there are
         three standard log streams, "tc_log", "servlet_log", and
         "JASPER_LOG".  

    Path: 

    The file to which to output this log, relative to
    TOMCAT_HOME.  If you omit a "path" value, then stderr or
    stdout will be used.

    Verbosity: 

    Threshold for which types of messages are displayed in the
    log.  Levels are inclusive; that is, "WARNING" level displays
    any log message marked as warning, error, or fatal.  Default
    level is WARNING.

    verbosityLevel values can be: 
       FATAL
       ERROR
       WARNING 
            INFORMATION
            DEBUG

    Timestamps:

    By default, logs print a timestamp in the form "yyyy-MM-dd
    hh:mm:ss" in front of each message.  To disable timestamps
    completely, set 'timestamp="no"'. To use the raw
    msec-since-epoch, which is more efficient, set
    'timestampFormat="msec"'.  If you want a custom format, you
    can use 'timestampFormat="hh:mm:ss"' following the syntax of
    java.text.SimpleDateFormat (see Javadoc API).  For a
    production environment, we recommend turning timestamps off,
    or setting the format to "msec".

    Custom Output:

    "Custom" means "normal looking".  "Non-custom" means
    "surrounded with funny xml tags".  In preparation for
    possibly disposing of "custom" altogether, now the default is
    'custom="yes"' (i.e. no tags)

    Per-component Debugging:

    Some components accept a "debug" attribute.  This further
    enhances log output.  If you set the "debug" level for a
    component, it may output extra debugging information.
    -->

    <!-- if you don't want messages on screen, add the attribute
            path="logs/tomcat.log" 
    to the Logger element below
    -->
    <Logger name="tc_log" 
            verbosityLevel = "INFORMATION" 
    />

    <Logger name="servlet_log" 
            path="logs/servlet.log"
    />

    <Logger name="JASPER_LOG" 
       path="logs/jasper.log"
            verbosityLevel = "INFORMATION" />

    <!-- You can add a "home" attribute to represent the "base" for 
         all relative paths. If none is set, the TOMCAT_HOME property
         will be used, and if not set "." will be used.
         webapps/, work/ and logs/ will be relative to this ( unless 
         set explicitely to absolute paths ).

         You can also specify a "randomClass" attribute, which determines 
         a subclass of java.util.Random will be used for generating session IDs.
         By default this is "java.security.SecureRandom". 
         Specifying "java.util.Random" will speed up Tomcat startup, 
         but it will cause sessions to be less secure.

         You can specify the "showDebugInfo" attribute to control whether
         debugging information is displayed in Tomcat's default responses.
         This debugging information includes:
             1. Stack traces for exceptions
             2. Request URI's that cause status codes >= 400
         The default is "true", so you must specify "false" to prevent
         the debug information from appearing.  Since the debugging
         information reveals internal details about what Tomcat is serving,
         set showDebugInfo="false" if you wish increased security.
      -->
    <ContextManager debug="0" workDir="work" showDebugInfo="true" >

        <!-- 
         ContextInterceptor className="org.apache.tomcat.context.LogEvents" 
         -->
        
        <ContextInterceptor className="org.apache.tomcat.context.AutoSetup" />

        <ContextInterceptor 
            className="org.apache.tomcat.context.WebXmlReader" />

        <!-- Uncomment out if you have JDK1.2 and want to use policy 
        <ContextInterceptor 
            className="org.apache.tomcat.context.PolicyInterceptor" />
        -->

        <ContextInterceptor 
            className="org.apache.tomcat.context.LoaderInterceptor" />
        <ContextInterceptor 
            className="org.apache.tomcat.context.DefaultCMSetter" />
        <ContextInterceptor 
            className="org.apache.tomcat.context.WorkDirInterceptor" />

        <!-- Request processing -->
        <!-- Session interceptor will extract the session id from cookies and 
             deal with

    URL rewriting ( by fixing the URL ).  If you wish to
             suppress the use of cookies for session identifiers, change the
             "noCookies" attribute to "true"
          -->
        <RequestInterceptor 
            className="org.apache.tomcat.request.SessionInterceptor"
            noCookies="false" />

        <!-- Find the

    container ( context and prefix/extension map ) 
             for a request.
          -->
        <RequestInterceptor 
            className="org.apache.tomcat.request.SimpleMapper1" 
            debug="0" />

        <!-- Non-standard invoker, for backward compat. ( /servlet/* )
             You can modify the prefix that is matched by adjusting the
             "prefix" parameter below.  Be sure your modified pattern
             starts and ends with a slash.

             NOTE:  This prefix applies to *all* web applications that
             are running in this instance of Tomcat.
          -->
        <RequestInterceptor 
            className="org.apache.tomcat.request.InvokerInterceptor" 
            debug="0" prefix="/servlet/" />

        <!-- "default" handler - static files and dirs.  Set the
             "suppress" property to "true" to suppress directory listings
             when no welcome file is present.

             NOTE:  This setting applies to *all* web applications that
             are running in this instance of Tomcat.
          -->
        <RequestInterceptor 
            className="org.apache.tomcat.request.StaticInterceptor" 
            debug="0" suppress="false" />

        <!-- Plug a session manager. You can plug in more advanced session
             modules.
          -->
        <RequestInterceptor 
            className="org.apache.tomcat.session.StandardSessionInterceptor" />

        <!-- Check if the request requires an authenticated role.
          -->
        <RequestInterceptor 
            className="org.apache.tomcat.request.AccessInterceptor" 
            debug="0" />

        <!-- Check permissions using the simple xml file. You can 
             plug more advanced authentication modules.
          -->
        <RequestInterceptor 
            className="org.apache.tomcat.request.SimpleRealm" 
            debug="0" />

       <!-- UnComment the following and comment out the
            above to get a JDBC realm.
            Other options for driverName: 
              driverName="oracle.jdbc.driver.OracleDriver"
              connectionURL="jdbc:oracle:thin:@ntserver:1521:ORCL"
              connectionName="scott"
              connectionPassword="tiger"

              driverName="org.gjt.mm.mysql.Driver"
              connectionURL="jdbc:mysql://localhost/authority"
              connectionName="test"
              connectionPassword="test"

            "connectionName" and "connectionPassword" are optional.
        -->
        <!--
        <RequestInterceptor 
            className="org.apache.tomcat.request.JDBCRealm" 
            debug="99" 
       driverName="sun.jdbc.odbc.JdbcOdbcDriver" 
       connectionURL="jdbc:odbc:TOMCAT" 
       userTable="users" 
            userNameCol="user_name" 
            userCredCol="user_pass" 
       userRoleTable="user_roles" 
            roleNameCol="role_name" />
        -->

        <!-- Loaded last since JSP's that load-on-startup use request handling -->
        <ContextInterceptor 
            className="org.apache.tomcat.context.LoadOnStartupInterceptor" />

      <!-- Connectors -->

        <!-- Normal HTTP -->
        <Connector className="org.apache.tomcat.service.PoolTcpConnector">
            <Parameter name="handler" 
                value="org.apache.tomcat.service.http.HttpConnectionHandler"/>
            <Parameter name="port" 
                value="8080"/>
        </Connector>

        <!--
            Uncomment this for SSL support. 
            You _need_ to set up a server certificate if you want this
            to work, and you need JSSE.
            1. Add JSSE jars to CLASSPATH 
            2. Edit java.home/jre/lib/security/java.security
               Add:
               security.provider.2=com.sun.net.ssl.internal.ssl.Provider
            3. Do: keytool -genkey -alias tomcat -keyalg RSA
               RSA is essential to work with Netscape and IIS.
               Use "changeit" as password. ( or add keypass attribute )
               You don't need to sign the certificate.
 
            You can set parameter keystore and keypass if you want 
            to change the default ( user.home/.keystore with changeit )
         -->
        <!--
        <Connector className="org.apache.tomcat.service.PoolTcpConnector">
            <Parameter name="handler" 
                value="org.apache.tomcat.service.http.HttpConnectionHandler"/>
            <Parameter name="port" 
                value="8443"/>
            <Parameter name="socketFactory" 
                value="org.apache.tomcat.net.SSLSocketFactory" />
        </Connector>
        -->

        <!-- Apache AJP12 support. This is also used to shut down tomcat.
          -->
        <Connector className="org.apache.tomcat.service.PoolTcpConnector">
            <Parameter name="handler" 
       value="org.apache.tomcat.service.connector.Ajp12ConnectionHandler"/>
            <Parameter name="port" value="8007"/>
        </Connector>

        <!-- Special webapps ->
        <!-- You don't need this if you place your app in webapps/
             and use defaults. 
             For security you'll also need to edit tomcat.policy

             Defaults are: debug=0, reloadable=true, trusted=false
             (trusted allows you to access tomcat internal objects 
             with FacadeManager ), crossContext=true (allows you to
             access other contexts via ServletContext.getContext())
 
             If security manager is enabled, you'll have read perms.
             in the webapps dir and read/write in the workdir.
         -->

        <Context path="/examples" 
                 docBase="webapps/examples" 
                 crossContext="false"
                 debug="0" 
                 reloadable="true" > 
        </Context>

        <!-- Admin context will use tomcat.core to add/remove/get info about
             the webapplications and tomcat internals. 
             By default it is not trusted - i.e. it is not allowed access to 
             tomcat internals, only informations that are available to all 
             servlets are visible.

             If you change this to true, make sure you set a password.
          -->
        <Context path="/admin" 
                 docBase="webapps/admin" 
                 crossContext="true"
                 debug="0" 
                 reloadable="true" 
                 trusted="false" > 
        </Context>

        <!-- Virtual host example - 
             In "127.0.0.1" virtual host we'll reverse "/" and 
             "/examples"
             (XXX need a better example )
             (use  "http://127.0.0.1/examples" )
        <Host name="127.0.0.1" >
           <Context path="" 
                    docBase="webapps/examples" />
           <Context path="/examples" 
                    docBase="webapps/ROOT" />
        </Host>
         -->

    </ContextManager>
</Server>