View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache license, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License. You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the license for the specific language governing permissions and
15   * limitations under the license.
16   */
17  package org.apache.logging.log4j.core.jmx;
18  
19  import java.awt.BorderLayout;
20  import java.awt.Color;
21  import java.awt.Font;
22  import java.io.IOException;
23  import java.io.PrintWriter;
24  import java.io.StringWriter;
25  import java.util.HashMap;
26  import java.util.Map;
27  
28  import javax.management.InstanceNotFoundException;
29  import javax.management.MalformedObjectNameException;
30  import javax.management.Notification;
31  import javax.management.NotificationFilterSupport;
32  import javax.management.NotificationListener;
33  import javax.management.ObjectName;
34  import javax.management.remote.JMXConnector;
35  import javax.management.remote.JMXConnectorFactory;
36  import javax.management.remote.JMXServiceURL;
37  import javax.swing.JFrame;
38  import javax.swing.JOptionPane;
39  import javax.swing.JPanel;
40  import javax.swing.JScrollPane;
41  import javax.swing.JTabbedPane;
42  import javax.swing.JTextArea;
43  import javax.swing.SwingUtilities;
44  import javax.swing.UIManager;
45  import javax.swing.UIManager.LookAndFeelInfo;
46  
47  /**
48   * GUI that connects to a Java process via JMX and allows the user to view and
49   * modify the log4j2 configuration, as well as monitor status logs.
50   * 
51   * @see http 
52   *      ://docs.oracle.com/javase/6/docs/technotes/guides/management/jconsole
53   *      .html
54   */
55  public class ClientGUI extends JPanel implements NotificationListener {
56      private static final long serialVersionUID = -253621277232291174L;
57      private Client client;
58      private JTextArea statusLogTextArea;
59      private JTabbedPane tabbedPane;
60  
61      public ClientGUI(Client client) throws InstanceNotFoundException,
62              MalformedObjectNameException, IOException {
63          this.client = Assert.isNotNull(client, "client");
64          createWidgets();
65          populateWidgets();
66          registerListeners();
67      }
68  
69      private void createWidgets() {
70          statusLogTextArea = new JTextArea();
71          statusLogTextArea.setEditable(false);
72          statusLogTextArea.setBackground(this.getBackground());
73          statusLogTextArea.setForeground(Color.black);
74          statusLogTextArea.setFont(new Font("Monospaced", Font.PLAIN,
75                  statusLogTextArea.getFont().getSize()));
76          JScrollPane scrollStatusLog = new JScrollPane(statusLogTextArea);
77  
78          tabbedPane = new JTabbedPane();
79          tabbedPane.addTab("StatusLogger", scrollStatusLog);
80  
81          this.setLayout(new BorderLayout());
82          this.add(tabbedPane, BorderLayout.CENTER);
83      }
84  
85      private void populateWidgets() {
86  
87          StatusLoggerAdminMBean statusAdmin = client.getStatusLoggerAdmin();
88          String[] messages = statusAdmin.getStatusDataHistory();
89          for (String message : messages) {
90              statusLogTextArea.append(message + "\n");
91          }
92  
93          for (LoggerContextAdminMBean ctx : client.getLoggerContextAdmins()) {
94              ClientEditConfigPanel editor = new ClientEditConfigPanel(ctx);
95              tabbedPane.addTab("LoggerContext: " + ctx.getName(), editor);
96          }
97      }
98  
99      private void registerListeners() throws InstanceNotFoundException,
100             MalformedObjectNameException, IOException {
101         NotificationFilterSupport filter = new NotificationFilterSupport();
102         filter.enableType(StatusLoggerAdminMBean.NOTIF_TYPE_MESSAGE);
103         ObjectName objName = new ObjectName(StatusLoggerAdminMBean.NAME);
104         client.getConnection().addNotificationListener(objName, this, filter,
105                 null);
106     }
107 
108     @Override
109     public void handleNotification(Notification notif, Object paramObject) {
110         if (StatusLoggerAdminMBean.NOTIF_TYPE_MESSAGE.equals(notif.getType())) {
111             statusLogTextArea.append(notif.getMessage() + "\n");
112         }
113     }
114 
115     /**
116      * Connects to the specified location and shows this panel in a window.
117      * <p>
118      * Useful links:
119      * http://www.componative.com/content/controller/developer/insights
120      * /jconsole3/
121      * 
122      * @param args
123      *            must have at least one parameter, which specifies the location
124      *            to connect to. Must be of the form {@code host:port} or
125      *            {@code service:jmx:rmi:///jndi/rmi://<host>:<port>/jmxrmi} or
126      *            {@code service:jmx:rmi://<host>:<port>/jndi/rmi://<host>:<port>/jmxrmi}
127      */
128     public static void main(String[] args) throws Exception {
129         if (args.length < 1) {
130             usage();
131             return;
132         }
133         String serviceUrl = args[0];
134         if (!serviceUrl.startsWith("service:jmx")) {
135             serviceUrl = "service:jmx:rmi:///jndi/rmi://" + args[0] + "/jmxrmi";
136         }
137         JMXServiceURL url = new JMXServiceURL(serviceUrl);
138         Map<String, String> paramMap = new HashMap<String, String>();
139         for (Object objKey : System.getProperties().keySet()) {
140             String key = (String) objKey;
141             paramMap.put(key, System.getProperties().getProperty(key));
142         }
143         JMXConnector connector = JMXConnectorFactory.connect(url, paramMap);
144         final Client client = new Client(connector);
145         final String title = "Log4J2 JMX Client - " + url;
146 
147         SwingUtilities.invokeLater(new Runnable() {
148             @Override
149             public void run() {
150                 installLookAndFeel();
151                 try {
152                     ClientGUI gui = new ClientGUI(client);
153                     JFrame frame = new JFrame(title);
154                     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
155                     frame.getContentPane().add(gui, BorderLayout.CENTER);
156                     frame.pack();
157                     frame.setVisible(true);
158                 } catch (Exception ex) {
159                     // if console is visible, print error so that
160                     // the stack trace remains visible after error dialog is
161                     // closed
162                     ex.printStackTrace();
163 
164                     // show error in dialog: there may not be a console window
165                     // visible
166                     StringWriter sr = new StringWriter();
167                     ex.printStackTrace(new PrintWriter(sr));
168                     JOptionPane.showMessageDialog(null, sr.toString(), "Error",
169                             JOptionPane.ERROR_MESSAGE);
170                 }
171             }
172         });
173     }
174 
175     private static void usage() {
176         String me = ClientGUI.class.getName();
177         System.err.println("Usage: java " + me + " <host>:<port>");
178         System.err.println("   or: java " + me
179                 + " service:jmx:rmi:///jndi/rmi://<host>:<port>/jmxrmi");
180         String longAdr = " service:jmx:rmi://<host>:<port>/jndi/rmi://<host>:<port>/jmxrmi";
181         System.err.println("   or: java " + me + longAdr);
182     }
183 
184     private static void installLookAndFeel() {
185         try {
186             for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
187                 if ("Nimbus".equals(info.getName())) {
188                     UIManager.setLookAndFeel(info.getClassName());
189                     return;
190                 }
191             }
192         } catch (Exception ex) {
193             ex.printStackTrace();
194         }
195         try {
196             UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
197         } catch (Exception e) {
198             e.printStackTrace();
199         }
200     }
201 }