1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.log4j.chainsaw;
18
19 import java.awt.Component;
20 import java.awt.Dimension;
21 import java.awt.GridBagConstraints;
22 import java.awt.GridBagLayout;
23 import java.awt.GridLayout;
24 import java.awt.event.ActionEvent;
25 import java.awt.event.ActionListener;
26 import java.awt.event.FocusEvent;
27 import java.awt.event.FocusListener;
28 import java.io.File;
29 import java.net.MalformedURLException;
30 import java.net.URL;
31
32 import javax.swing.AbstractAction;
33 import javax.swing.BorderFactory;
34 import javax.swing.Box;
35 import javax.swing.ButtonGroup;
36 import javax.swing.DefaultComboBoxModel;
37 import javax.swing.DefaultListCellRenderer;
38 import javax.swing.JButton;
39 import javax.swing.JCheckBox;
40 import javax.swing.JComboBox;
41 import javax.swing.JFileChooser;
42 import javax.swing.JFrame;
43 import javax.swing.JLabel;
44 import javax.swing.JList;
45 import javax.swing.JPanel;
46 import javax.swing.JRadioButton;
47 import javax.swing.JTextArea;
48 import javax.swing.SwingUtilities;
49 import javax.swing.event.ListDataEvent;
50 import javax.swing.event.ListDataListener;
51 import javax.swing.filechooser.FileFilter;
52
53 import org.apache.log4j.LogManager;
54 import org.apache.log4j.Logger;
55 import org.apache.log4j.chainsaw.prefs.SettingsManager;
56 import org.apache.log4j.net.PortBased;
57 import org.apache.log4j.net.SocketAppender;
58 import org.apache.log4j.net.SocketHubReceiver;
59 import org.apache.log4j.net.SocketReceiver;
60
61
62 /***
63 * A dialog panel to inform the user that they do not have
64 * Receiver's defined, and prompting them to either
65 * load a Log4j Log file, search for a Log4j configuration file
66 * or use the GUI to define the Receivers
67 *
68 * @author Paul Smith
69 */
70 class NoReceiversWarningPanel extends JPanel {
71
72 private final JComboBox previousConfigs = new JComboBox();
73
74 private final JRadioButton simpleReceiver = new JRadioButton(
75 "Let me use a simple Receiver:");
76
77 private final JRadioButton justLoadingFile = new JRadioButton(
78 "I'm fine thanks, don't worry");
79 private final JRadioButton searchOption = new JRadioButton(
80 "Let me search for a configuration file");
81 private final JRadioButton chainsawSavedConfigOption = new JRadioButton(
82 "Load configuration file saved by Chainsaw");
83 private final JRadioButton manualOption = new JRadioButton(
84 "Let me define Receivers manually");
85 private final JButton okButton = new JButton("Ok");
86 private final PanelModel model = new PanelModel();
87 final DefaultComboBoxModel configModel = new DefaultComboBoxModel();
88
89 final DefaultComboBoxModel simpleReceiverModel = new DefaultComboBoxModel();
90 final DefaultComboBoxModel simplePortModel = new DefaultComboBoxModel();
91
92 private boolean dontWarnMeAgain = false;
93
94 private final Logger logger = LogManager.getLogger(NoReceiversWarningPanel.class);
95
96 NoReceiversWarningPanel() {
97 initComponents();
98 }
99
100 /***
101 * Returns the current Model/state of the chosen options by the user.
102 * @return
103 */
104 PanelModel getModel() {
105
106 return model;
107 }
108
109 /***
110 * Clients of this panel can configure the ActionListener to be used
111 * when the user presses the OK button, so they can read
112 * back this Panel's model top determine what to do.
113 * @param actionListener
114 */
115 void setOkActionListener(ActionListener actionListener) {
116 okButton.addActionListener(actionListener);
117 }
118
119 /***
120 * Sets up all the GUI components for this paenl
121 */
122 private void initComponents() {
123 setLayout(new GridBagLayout());
124
125 GridBagConstraints gc = new GridBagConstraints();
126
127 setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15));
128
129 gc.gridx = 1;
130 gc.fill = GridBagConstraints.BOTH;
131 gc.weightx = 1.0;
132 gc.weighty = 1.0;
133
134 JTextArea label = new JTextArea(
135 "You will not be able to receive events from a Remote source unless you define one in the Log4J configuration file.\n");
136 label.setWrapStyleWord(true);
137 label.setLineWrap(true);
138 label.setEditable(false);
139 label.setOpaque(false);
140 label.setFont(getFont());
141
142 add(label, gc);
143
144 gc.weightx = 0;
145 gc.weighty = 0;
146 gc.gridy = 2;
147 add(Box.createVerticalStrut(20), gc);
148
149 JPanel optionpanel = new JPanel();
150 optionpanel.setLayout(new GridLayout(5, 1, 3, 3));
151 optionpanel.setBackground(getBackground());
152 optionpanel.setBorder(BorderFactory.createEtchedBorder());
153
154 final ButtonGroup optionGroup = new ButtonGroup();
155
156 simpleReceiver.setToolTipText(
157 "Creates one of the standard Receivers on one of the standard port");
158 simpleReceiver.setMnemonic('p');
159
160 searchOption.setToolTipText(
161 "Allows you to choose a Log4J Configuration file that contains Receiver definitions");
162
163 searchOption.setMnemonic('S');
164
165 chainsawSavedConfigOption.setToolTipText(
166 "Allows you to load Receiver definitions saved by Chanisaw previously");
167
168 chainsawSavedConfigOption.setMnemonic('C');
169
170
171 manualOption.setToolTipText(
172 "Opens the Receivers panel so you can define them via a GUI");
173
174 manualOption.setMnemonic('m');
175
176 justLoadingFile.setToolTipText(
177 "Use this if you just want to view a Log4J Log file stored somewhere");
178
179 justLoadingFile.setMnemonic('I');
180
181
182 manualOption.setOpaque(false);
183 justLoadingFile.setOpaque(false);
184
185 optionGroup.add(searchOption);
186 optionGroup.add(chainsawSavedConfigOption);
187 optionGroup.add(manualOption);
188 optionGroup.add(justLoadingFile);
189 optionGroup.add(simpleReceiver);
190
191 chainsawSavedConfigOption.setEnabled(getModel().isChinsawConfigFileExists());
192
193 gc.gridy = 3;
194
195
196 configModel.removeAllElements();
197
198 previousConfigs.setModel(configModel);
199 previousConfigs.setOpaque(false);
200 previousConfigs.setBackground(getBackground());
201 previousConfigs.setToolTipText(
202 "Previously loaded configurations can be chosen here");
203
204 previousConfigs.setEditable(true);
205
206 previousConfigs.getModel().addListDataListener(new ListDataListener() {
207 private void validateUrl() {
208 okButton.setEnabled(isValidConfigURL());
209 }
210
211 public void contentsChanged(ListDataEvent e) {
212 validateUrl();
213 }
214
215 public void intervalAdded(ListDataEvent e) {
216 validateUrl();
217 }
218
219 public void intervalRemoved(ListDataEvent e) {
220 validateUrl();
221 }
222 });
223
224 previousConfigs.setMaximumSize(new Dimension(200,
225 (int) previousConfigs.getPreferredSize().getHeight()));
226 previousConfigs.setPreferredSize(previousConfigs.getMaximumSize());
227 previousConfigs.getEditor().getEditorComponent().addFocusListener(
228 new FocusListener() {
229 public void focusGained(FocusEvent e) {
230 selectAll();
231 }
232
233 private void selectAll() {
234 previousConfigs.getEditor().selectAll();
235 }
236
237 public void focusLost(FocusEvent e) {
238 }
239 });
240
241 final JButton searchButton = new JButton(new AbstractAction(
242 "Browse...") {
243 public void actionPerformed(ActionEvent e) {
244
245 try {
246
247 URL url = browseForConfig();
248
249 if (url != null) {
250 getModel().configUrl = url;
251 configModel.addElement(url);
252 previousConfigs.getModel().setSelectedItem(
253 url);
254 }
255 } catch (Exception ex) {
256 logger.error(
257 "Error browswing for Configuration file", ex);
258 }
259 }
260 });
261
262 searchButton.setToolTipText(
263 "Shows a File Open dialog to allow you to find a configuration file");
264
265
266 simplePortModel.addElement(new PortBased() {
267
268 private void unsupported() {
269 throw new UnsupportedOperationException(
270 "Should not be used in this context");
271 }
272
273 public String getName() {
274 unsupported();
275
276 return null;
277 }
278
279 public boolean isActive() {
280 unsupported();
281
282 return false;
283 }
284
285 public int getPort() {
286
287 return 4445;
288 }
289
290 public String toString() {
291
292 return getPort() + " (Old style/standard Chainsaw port)";
293 }
294 });
295
296 simplePortModel.addElement(new PortBased() {
297
298 private void unsupported() {
299 throw new UnsupportedOperationException(
300 "Should not be used in this context");
301 }
302
303 public String getName() {
304 unsupported();
305
306 return null;
307 }
308
309 public boolean isActive() {
310 unsupported();
311
312 return false;
313 }
314
315 public int getPort() {
316
317 return SocketAppender.DEFAULT_PORT;
318 }
319
320 public String toString() {
321
322 return getPort() + " (Default SocketAppender port)";
323 }
324 });
325
326 JPanel simpleSocketPanel = new JPanel(new GridBagLayout());
327
328 GridBagConstraints simpleSocketGC = new GridBagConstraints();
329
330 simpleSocketPanel.add(simpleReceiver, simpleSocketGC);
331
332 final JComboBox socketCombo = new JComboBox(simplePortModel);
333
334
335 simpleReceiverModel.addElement(SocketReceiver.class);
336 simpleReceiverModel.addElement(SocketHubReceiver.class);
337
338 final JComboBox receiverCombo = new JComboBox(simpleReceiverModel);
339 receiverCombo.setEditable(false);
340 receiverCombo.setRenderer(new DefaultListCellRenderer() {
341 public Component getListCellRendererComponent(JList list,
342 Object value, int index, boolean isSelected,
343 boolean cellHasFocus) {
344
345 Component c = super.getListCellRendererComponent(list,
346 value, index, isSelected, cellHasFocus);
347
348 if (value instanceof Class) {
349
350 Class receiverClass = (Class) value;
351 JLabel cellLabel = (JLabel) c;
352 String shortenedName = receiverClass.getName()
353 .substring(
354 receiverClass.getName().lastIndexOf('.') + 1);
355 cellLabel.setText(shortenedName);
356 }
357
358 return c;
359 }
360
361 });
362
363 simpleSocketPanel.add(receiverCombo);
364 simpleSocketPanel.add(new JLabel(" on port "));
365 simpleSocketPanel.add(socketCombo, simpleSocketGC);
366
367 /***
368 * This listener activates/deactivates certain controls based on the current
369 * state of the options
370 */
371 ActionListener al = new ActionListener() {
372 public void actionPerformed(ActionEvent e) {
373 previousConfigs.setEnabled(e.getSource() == searchOption);
374 searchButton.setEnabled(e.getSource() == searchOption);
375 socketCombo.setEnabled(e.getSource() == simpleReceiver);
376 receiverCombo.setEnabled(e.getSource() == simpleReceiver);
377
378 if (optionGroup.isSelected(searchOption.getModel())) {
379 okButton.setEnabled(isValidConfigURL());
380 } else {
381 okButton.setEnabled(true);
382 }
383 }
384 };
385
386 searchOption.addActionListener(al);
387 chainsawSavedConfigOption.addActionListener(al);
388 manualOption.addActionListener(al);
389 justLoadingFile.addActionListener(al);
390 simpleReceiver.addActionListener(al);
391
392 justLoadingFile.doClick();
393
394 JPanel searchOptionPanel = new JPanel(new GridBagLayout());
395
396 searchOptionPanel.setOpaque(false);
397
398 GridBagConstraints searchGCC = new GridBagConstraints();
399
400 searchGCC.fill = GridBagConstraints.HORIZONTAL;
401 searchGCC.gridx = 1;
402 searchGCC.weightx = 0.0;
403 searchGCC.anchor = GridBagConstraints.WEST;
404 searchOptionPanel.add(searchOption, searchGCC);
405
406 searchGCC.fill = GridBagConstraints.NONE;
407 searchGCC.weightx = 1.0;
408 searchGCC.gridx = 2;
409 searchOptionPanel.add(Box.createHorizontalStrut(5), searchGCC);
410
411 searchGCC.gridx = 3;
412 searchGCC.weightx = 0.0;
413 searchOptionPanel.add(previousConfigs, searchGCC);
414
415 searchGCC.weightx = 0.0;
416 searchGCC.gridx = 4;
417 searchOptionPanel.add(Box.createHorizontalStrut(5), searchGCC);
418 searchGCC.gridx = 5;
419 searchOptionPanel.add(searchButton, searchGCC);
420
421
422
423
424
425
426
427 optionpanel.add(justLoadingFile);
428 optionpanel.add(simpleSocketPanel);
429 optionpanel.add(searchOptionPanel);
430 optionpanel.add(chainsawSavedConfigOption);
431 optionpanel.add(manualOption);
432
433 add(optionpanel, gc);
434
435 gc.gridy = GridBagConstraints.RELATIVE;
436 gc.weightx = 0;
437 gc.fill = GridBagConstraints.NONE;
438 gc.anchor = GridBagConstraints.SOUTHEAST;
439
440 add(Box.createVerticalStrut(20), gc);
441
442 okButton.setMnemonic('O');
443
444 final JCheckBox dontwarnIfNoReceiver = new JCheckBox(
445 "Don't show me this again");
446 JPanel okPanel = new JPanel();
447
448 okPanel.add(dontwarnIfNoReceiver);
449 okPanel.add(okButton);
450 add(okPanel, gc);
451
452 okButton.addActionListener(new ActionListener() {
453
454 public void actionPerformed(ActionEvent e) {
455 dontWarnMeAgain = dontwarnIfNoReceiver.isSelected();
456 }
457 });
458 }
459
460 /***
461 * Returns the URL chosen by the user for a Configuration file
462 * or null if they cancelled.
463 */
464 private URL browseForConfig() throws MalformedURLException {
465
466 JFileChooser chooser = new JFileChooser();
467 chooser.setDialogTitle("Search for Log4j configuration...");
468 chooser.setDialogType(JFileChooser.OPEN_DIALOG);
469 chooser.setFileFilter(new FileFilter() {
470 public boolean accept(File f) {
471
472 return f.isDirectory() ||
473 f.getName().endsWith(".properties") ||
474 f.getName().endsWith(".xml");
475 }
476
477 public String getDescription() {
478
479 return "Log4j Configuration file";
480 }
481 });
482
483 chooser.showOpenDialog(this);
484
485 File selectedFile = chooser.getSelectedFile();
486
487 if (selectedFile == null) {
488
489 return null;
490 }
491
492 if (!selectedFile.exists() || !selectedFile.canRead()) {
493
494 return null;
495 }
496
497 return chooser.getSelectedFile().toURI().toURL();
498 }
499
500 /***
501 * Determions if the Configuration URL is a valid url.
502 */
503 private boolean isValidConfigURL() {
504
505 if (previousConfigs.getSelectedItem() == null) {
506
507 return false;
508 }
509
510 String urlString = previousConfigs.getSelectedItem().toString();
511
512 try {
513 getModel().configUrl = new URL(urlString);
514
515 return true;
516 } catch (Exception ex) {
517 }
518
519 return false;
520 }
521
522 public static void main(String[] args) {
523
524 JFrame frame = new JFrame();
525 frame.getContentPane().add(new NoReceiversWarningPanel());
526 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
527 frame.pack();
528 frame.setVisible(true);
529 }
530
531 /***
532 * @return Returns the dontWarnMeAgain.
533 */
534 public final boolean isDontWarnMeAgain() {
535
536 return dontWarnMeAgain;
537 }
538
539 /***
540 * This class represents the model of the chosen options the user
541 * has configured.
542 *
543 */
544 class PanelModel {
545
546 private URL configUrl;
547 private File file;
548
549 public PanelModel(){
550 file = new File(SettingsManager.getInstance().getSettingsDirectory(), "receiver-configs.xml");
551 }
552
553 boolean isLoadLogFile() {
554
555 return justLoadingFile.isSelected();
556 }
557
558 boolean isSimpleReceiverMode() {
559
560 return simpleReceiver.isSelected();
561 }
562
563 int getSimplePort() {
564
565 return ((PortBased) simplePortModel.getSelectedItem()).getPort();
566 }
567
568 Class getSimpleReceiverClass() {
569
570 return (Class) simpleReceiverModel.getSelectedItem();
571 }
572
573 boolean isLoadConfig() {
574
575 return searchOption.isSelected();
576 }
577
578 boolean isLoadSavedConfigs() {
579
580 return chainsawSavedConfigOption.isSelected();
581 }
582
583 boolean isManualMode() {
584
585 return manualOption.isSelected();
586 }
587
588 public Object[] getRememberedConfigs() {
589
590 Object[] urls = new Object[configModel.getSize()];
591
592 for (int i = 0; i < configModel.getSize(); i++) {
593 urls[i] = configModel.getElementAt(i);
594 }
595
596 return urls;
597 }
598
599 public void setRememberedConfigs(final Object[] configs) {
600 SwingUtilities.invokeLater(new Runnable() {
601 public void run() {
602 configModel.removeAllElements();
603
604 for (int i = 0; i < configs.length; i++) {
605 configModel.addElement(configs[i]);
606 }
607 }
608 });
609 }
610
611 URL getConfigToLoad() {
612
613 return configUrl;
614 }
615
616 boolean isChinsawConfigFileExists(){
617
618 return file.exists();
619
620 }
621
622 URL getSavedConfigToLoad() {
623 try {
624 if (file.exists()){
625 return file.toURL();
626 } else {
627 logger.debug("No configuration file found");
628 }
629 } catch (MalformedURLException e) {
630 logger.error("Error laoding saved configurations by Chainsaw", e);
631 }
632 return null;
633 }
634 }
635 }