001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 * 
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 * 
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.log4j.chainsaw;
018
019import java.awt.BorderLayout;
020import java.awt.Dimension;
021import java.awt.event.WindowAdapter;
022import java.awt.event.WindowEvent;
023import java.io.IOException;
024import java.util.Properties;
025import javax.swing.BorderFactory;
026import javax.swing.JFrame;
027import javax.swing.JMenu;
028import javax.swing.JMenuBar;
029import javax.swing.JMenuItem;
030import javax.swing.JOptionPane;
031import javax.swing.JPanel;
032import javax.swing.JScrollPane;
033import javax.swing.JSplitPane;
034import javax.swing.JTable;
035import javax.swing.ListSelectionModel;
036import org.apache.log4j.Logger;
037import org.apache.log4j.PropertyConfigurator;
038
039/**
040 * The main application.
041 *
042 * @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
043 */
044public class Main
045    extends JFrame
046{
047    /** the default port number to listen on **/
048    private static final int DEFAULT_PORT = 4445;
049
050    /** name of property for port name **/
051    public static final String PORT_PROP_NAME = "chainsaw.port";
052
053    /** use to log messages **/
054    private static final Logger LOG = Logger.getLogger(Main.class);
055
056
057    /**
058     * Creates a new <code>Main</code> instance.
059     */
060    private Main() {
061        super("CHAINSAW - Log4J Log Viewer");
062        // create the all important model
063        final MyTableModel model = new MyTableModel();
064
065        //Create the menu bar.
066        final JMenuBar menuBar = new JMenuBar();
067        setJMenuBar(menuBar);
068        final JMenu menu = new JMenu("File");
069        menuBar.add(menu);
070
071        try {
072            final LoadXMLAction lxa = new LoadXMLAction(this, model);
073            final JMenuItem loadMenuItem = new JMenuItem("Load file...");
074            menu.add(loadMenuItem);
075            loadMenuItem.addActionListener(lxa);
076        } catch (NoClassDefFoundError e) {
077            LOG.info("Missing classes for XML parser", e);
078            JOptionPane.showMessageDialog(
079                this,
080                "XML parser not in classpath - unable to load XML events.",
081                "CHAINSAW",
082                JOptionPane.ERROR_MESSAGE);
083        } catch (Exception e) {
084            LOG.info("Unable to create the action to load XML files", e);
085            JOptionPane.showMessageDialog(
086                this,
087                "Unable to create a XML parser - unable to load XML events.",
088                "CHAINSAW",
089                JOptionPane.ERROR_MESSAGE);
090        }
091
092        final JMenuItem exitMenuItem = new JMenuItem("Exit");
093        menu.add(exitMenuItem);
094        exitMenuItem.addActionListener(ExitAction.INSTANCE);
095
096        // Add control panel
097        final ControlPanel cp = new ControlPanel(model);
098        getContentPane().add(cp, BorderLayout.NORTH);
099
100        // Create the table
101        final JTable table = new JTable(model);
102        table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
103        final JScrollPane scrollPane = new JScrollPane(table);
104        scrollPane.setBorder(BorderFactory.createTitledBorder("Events: "));
105        scrollPane.setPreferredSize(new Dimension(900, 300));
106
107        // Create the details
108        final JPanel details = new DetailPanel(table, model);
109        details.setPreferredSize(new Dimension(900, 300));
110
111        // Add the table and stack trace into a splitter
112        final JSplitPane jsp =
113            new JSplitPane(JSplitPane.VERTICAL_SPLIT, scrollPane, details);
114        getContentPane().add(jsp, BorderLayout.CENTER);
115
116        addWindowListener(new WindowAdapter() {
117                public void windowClosing(WindowEvent aEvent) {
118                    ExitAction.INSTANCE.actionPerformed(null);
119                }
120            });
121
122        pack();
123        setVisible(true);
124
125        setupReceiver(model);
126    }
127
128    /**
129     * Setup recieving messages.
130     *
131     * @param aModel a <code>MyTableModel</code> value
132     */
133    private void setupReceiver(MyTableModel aModel) {
134        int port = DEFAULT_PORT;
135        final String strRep = System.getProperty(PORT_PROP_NAME);
136        if (strRep != null) {
137            try {
138                port = Integer.parseInt(strRep);
139            } catch (NumberFormatException nfe) {
140                LOG.fatal("Unable to parse " + PORT_PROP_NAME +
141                          " property with value " + strRep + ".");
142                JOptionPane.showMessageDialog(
143                    this,
144                    "Unable to parse port number from '" + strRep +
145                    "', quitting.",
146                    "CHAINSAW",
147                    JOptionPane.ERROR_MESSAGE);
148                System.exit(1);
149            }
150        }
151
152        try {
153            final LoggingReceiver lr = new LoggingReceiver(aModel, port);
154            lr.start();
155        } catch (IOException e) {
156            LOG.fatal("Unable to connect to socket server, quiting", e);
157            JOptionPane.showMessageDialog(
158                this,
159                "Unable to create socket on port " + port + ", quitting.",
160                "CHAINSAW",
161                JOptionPane.ERROR_MESSAGE);
162            System.exit(1);
163        }
164    }
165
166
167    ////////////////////////////////////////////////////////////////////////////
168    // static methods
169    ////////////////////////////////////////////////////////////////////////////
170
171
172    /** initialise log4j **/
173    private static void initLog4J() {
174        final Properties props = new Properties();
175        props.setProperty("log4j.rootLogger", "DEBUG, A1");
176        props.setProperty("log4j.appender.A1",
177                          "org.apache.log4j.ConsoleAppender");
178        props.setProperty("log4j.appender.A1.layout",
179                          "org.apache.log4j.TTCCLayout");
180        PropertyConfigurator.configure(props);
181    }
182
183    /**
184     * The main method.
185     *
186     * @param aArgs ignored
187     */
188    public static void main(String[] aArgs) {
189        initLog4J();
190        new Main();
191    }
192}