View Javadoc
1   package com.jsql.view.swing.console;
2   
3   import com.jsql.util.LogLevelUtil;
4   import com.jsql.view.swing.util.UiUtil;
5   import org.apache.logging.log4j.Level;
6   import org.apache.logging.log4j.core.*;
7   import org.apache.logging.log4j.core.appender.AbstractAppender;
8   import org.apache.logging.log4j.core.config.Property;
9   import org.apache.logging.log4j.core.config.plugins.Plugin;
10  import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
11  import org.apache.logging.log4j.core.config.plugins.PluginElement;
12  import org.apache.logging.log4j.core.config.plugins.PluginFactory;
13  import org.apache.logging.log4j.core.layout.PatternLayout;
14  
15  import javax.swing.*;
16  import javax.swing.text.SimpleAttributeSet;
17  import javax.swing.text.StyleConstants;
18  import java.awt.*;
19  import java.nio.charset.StandardCharsets;
20  import java.util.AbstractMap;
21  import java.util.Optional;
22  import java.util.stream.Stream;
23  
24  /**
25   * Log4j2
26   * LOGGER.info(e)
27   * => No query string
28   * LOGGER.info(e.getMessage())
29   * => com.jsql.model.exception.InjectionFailureException: No query string
30   * LOGGER.info(e, e)
31   * => com.jsql.model.exception.InjectionFailureException: No query string + Stacktrace
32   */
33  @Plugin(
34      name = "JTextPaneAppender",
35      category = Core.CATEGORY_NAME,
36      elementType = Appender.ELEMENT_TYPE,
37      printObject = true
38  )
39  public class JTextPaneAppender extends AbstractAppender {
40      
41      // Main console
42      private static SimpleConsoleAdapter consoleTextPane;
43      
44      // Java console
45      private static JavaConsoleAdapter javaTextPane;
46  
47      public static final SimpleAttributeSet ATTRIBUTE_WARN = new SimpleAttributeSet();
48      public static final SimpleAttributeSet ATTRIBUTE_INFORM = new SimpleAttributeSet();
49      public static final SimpleAttributeSet ATTRIBUTE_SUCCESS = new SimpleAttributeSet();
50      public static final SimpleAttributeSet ATTRIBUTE_ALL = new SimpleAttributeSet();
51      
52      static {
53          Stream.of(
54              new AbstractMap.SimpleEntry<>(ATTRIBUTE_WARN, Color.RED),
55              new AbstractMap.SimpleEntry<>(ATTRIBUTE_INFORM, Color.BLUE),
56              new AbstractMap.SimpleEntry<>(ATTRIBUTE_SUCCESS, UiUtil.COLOR_GREEN),
57              new AbstractMap.SimpleEntry<>(ATTRIBUTE_ALL, Color.BLACK)
58          )
59          .forEach(entry -> {
60              
61              StyleConstants.setFontFamily(entry.getKey(), UiUtil.FONT_NAME_MONO_NON_ASIAN);
62              StyleConstants.setFontSize(entry.getKey(), UiUtil.FONT_SIZE_MONO_NON_ASIAN);
63              StyleConstants.setForeground(entry.getKey(), entry.getValue());
64          });
65      }
66      
67      private JTextPaneAppender(String name, Layout<?> layout, Filter filter, boolean ignoreExceptions) {
68          super(name, filter, layout, ignoreExceptions, Property.EMPTY_ARRAY);
69      }
70  
71      @SuppressWarnings({ "unused", "rawtypes" })
72      @PluginFactory
73      public static JTextPaneAppender createAppender(
74          @PluginAttribute("name") String name,
75          @PluginAttribute("ignoreExceptions") boolean ignoreExceptions,
76          @PluginElement("Layout") Layout layout,
77          @PluginElement("Filters") Filter filter
78      ) {
79          if (name == null) {
80              
81              LOGGER.log(LogLevelUtil.CONSOLE_JAVA, "No name provided for JTextPaneAppender");
82              return null;
83          }
84  
85          var layoutTextPane = Optional.ofNullable(layout).orElse(PatternLayout.createDefaultLayout());
86          
87          return new JTextPaneAppender(name, layoutTextPane, filter, ignoreExceptions);
88      }
89  
90      @Override
91      public void append(LogEvent event) {
92          
93          // Avoid errors which might occur in headless mode
94          // or logging that occurs before consoles are available
95          if (consoleTextPane == null || javaTextPane == null) {
96              return;
97          }
98          
99          var messageLogEvent = new String[] {
100             new String(this.getLayout().toByteArray(event), StandardCharsets.UTF_8)
101         };
102 
103         if (messageLogEvent.length == 0) {  // fixes #95664
104             return;
105         }
106         
107         var level = event.getLevel().intLevel();
108         
109         SwingUtilities.invokeLater(() -> {
110             
111             String message = messageLogEvent[0];
112 
113             if (level == LogLevelUtil.CONSOLE_JAVA.intLevel()) {
114                 javaTextPane.append(message, ATTRIBUTE_WARN);
115             } else if (level == LogLevelUtil.CONSOLE_ERROR.intLevel()) {
116                 consoleTextPane.append(message, ATTRIBUTE_WARN);
117             } else if (level == LogLevelUtil.CONSOLE_INFORM.intLevel()) {
118                 consoleTextPane.append(message, ATTRIBUTE_INFORM);
119             } else if (level == LogLevelUtil.CONSOLE_SUCCESS.intLevel()) {
120                 consoleTextPane.append(message, ATTRIBUTE_SUCCESS);
121             } else if (level != LogLevelUtil.IGNORE.intLevel() && level != Level.ERROR.intLevel()) {  // ignore & stdout when unhandled exception
122                 consoleTextPane.append(message, ATTRIBUTE_ALL);
123             }
124         });
125     }
126     
127     /**
128      * Register the java console.
129      * @param javaConsole
130      */
131     public static void register(JavaConsoleAdapter javaConsole) {
132         JTextPaneAppender.javaTextPane = javaConsole;
133     }
134 
135     /**
136      * Register the default console.
137      * @param consoleColored
138      */
139     public static void register(SimpleConsoleAdapter consoleColored) {
140         JTextPaneAppender.consoleTextPane = consoleColored;
141     }
142 }