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}