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     */
017    package org.apache.logging.log4j.core.pattern;
018    
019    import java.lang.reflect.Constructor;
020    import java.lang.reflect.InvocationTargetException;
021    import java.util.Arrays;
022    import java.util.List;
023    
024    import org.apache.logging.log4j.core.LogEvent;
025    import org.apache.logging.log4j.core.config.Configuration;
026    import org.apache.logging.log4j.core.config.plugins.Plugin;
027    import org.apache.logging.log4j.core.layout.PatternLayout;
028    
029    /**
030     * Style pattern converter. Adds ANSI color styling to the result of the enclosed pattern.
031     */
032    public abstract class AbstractStyleNameConverter extends LogEventPatternConverter /*TODO: implements AnsiConverter*/ {
033    
034        private final List<PatternFormatter> formatters;
035    
036        private final String style;
037    
038        /**
039         * Constructs the converter.
040         *
041         * @param formatters The PatternFormatters to generate the text to manipulate.
042         * @param styling The styling that should encapsulate the pattern.
043         */
044        protected AbstractStyleNameConverter(final String name, final List<PatternFormatter> formatters,
045                                             final String styling) {
046            super(name, "style");
047            this.formatters = formatters;
048            this.style = styling;
049        }
050    
051        /**
052         * Black style pattern converter. Adds ANSI color styling to the result of the enclosed pattern.
053         */
054        @Plugin(name = Black.NAME, category = "Converter")
055        @ConverterKeys(Black.NAME)
056        public static final class Black extends AbstractStyleNameConverter {
057    
058            /** Black */
059            protected static final String NAME = "black";
060    
061            /**
062             * Constructs the converter. This constructor must be public.
063             *
064             * @param formatters The PatternFormatters to generate the text to manipulate.
065             * @param styling The styling that should encapsulate the pattern.
066             */
067            public Black(final List<PatternFormatter> formatters, final String styling) {
068                super(NAME, formatters, styling);
069            }
070    
071            /**
072             * Gets an instance of the class (called via reflection).
073             *
074             * @param config The current Configuration.
075             * @param options The pattern options, may be null. If the first element is "short", only the first line of the
076             *            throwable will be formatted.
077             * @return new instance of class or null
078             */
079            public static Black newInstance(final Configuration config, final String[] options) {
080                return newInstance(Black.class, NAME, config, options);
081            }
082        }
083    
084        /**
085         * Blue style pattern converter. Adds ANSI color styling to the result of the enclosed pattern.
086         */
087        @Plugin(name = Blue.NAME, category = "Converter")
088        @ConverterKeys(Blue.NAME)
089        public static final class Blue extends AbstractStyleNameConverter {
090    
091            /** Blue */
092            protected static final String NAME = "blue";
093    
094            /**
095             * Constructs the converter. This constructor must be public.
096             *
097             * @param formatters The PatternFormatters to generate the text to manipulate.
098             * @param styling The styling that should encapsulate the pattern.
099             */
100            public Blue(final List<PatternFormatter> formatters, final String styling) {
101                super(NAME, formatters, styling);
102            }
103    
104            /**
105             * Gets an instance of the class (called via reflection).
106             *
107             * @param config The current Configuration.
108             * @param options The pattern options, may be null. If the first element is "short", only the first line of the
109             *                throwable will be formatted.
110             * @return new instance of class or null
111             */
112            public static Blue newInstance(final Configuration config, final String[] options) {
113                return newInstance(Blue.class, NAME, config, options);
114            }
115        }
116    
117        /**
118         * Cyan style pattern converter. Adds ANSI color styling to the result of the enclosed pattern.
119         */
120        @Plugin(name = Cyan.NAME, category = "Converter")
121        @ConverterKeys(Cyan.NAME)
122        public static final class Cyan extends AbstractStyleNameConverter {
123    
124            /** Cyan */
125            protected static final String NAME = "cyan";
126    
127            /**
128             * Constructs the converter. This constructor must be public.
129             *
130             * @param formatters The PatternFormatters to generate the text to manipulate.
131             * @param styling The styling that should encapsulate the pattern.
132             */
133            public Cyan(final List<PatternFormatter> formatters, final String styling) {
134                super(NAME, formatters, styling);
135            }
136    
137            /**
138             * Gets an instance of the class (called via reflection).
139             *
140             * @param config The current Configuration.
141             * @param options The pattern options, may be null. If the first element is "short", only the first line of the
142             *                throwable will be formatted.
143             * @return new instance of class or null
144             */
145            public static Cyan newInstance(final Configuration config, final String[] options) {
146                return newInstance(Cyan.class, NAME, config, options);
147            }
148        }
149    
150        /**
151         * Green style pattern converter. Adds ANSI color styling to the result of the enclosed pattern.
152         */
153        @Plugin(name = Green.NAME, category = "Converter")
154        @ConverterKeys(Green.NAME)
155        public static final class Green extends AbstractStyleNameConverter {
156    
157            /** Green */
158            protected static final String NAME = "green";
159    
160            /**
161             * Constructs the converter. This constructor must be public.
162             *
163             * @param formatters The PatternFormatters to generate the text to manipulate.
164             * @param styling The styling that should encapsulate the pattern.
165             */
166            public Green(final List<PatternFormatter> formatters, final String styling) {
167                super(NAME, formatters, styling);
168            }
169    
170            /**
171             * Gets an instance of the class (called via reflection).
172             *
173             * @param config The current Configuration.
174             * @param options The pattern options, may be null. If the first element is "short", only the first line of the
175             *                throwable will be formatted.
176             * @return new instance of class or null
177             */
178            public static Green newInstance(final Configuration config, final String[] options) {
179                return newInstance(Green.class, NAME, config, options);
180            }
181        }
182    
183        /**
184         * Magenta style pattern converter. Adds ANSI color styling to the result of the enclosed pattern.
185         */
186        @Plugin(name = Magenta.NAME, category = "Converter")
187        @ConverterKeys(Magenta.NAME)
188        public static final class Magenta extends AbstractStyleNameConverter {
189    
190            /** Magenta */
191            protected static final String NAME = "magenta";
192    
193            /**
194             * Constructs the converter. This constructor must be public.
195             *
196             * @param formatters The PatternFormatters to generate the text to manipulate.
197             * @param styling The styling that should encapsulate the pattern.
198             */
199            public Magenta(final List<PatternFormatter> formatters, final String styling) {
200                super(NAME, formatters, styling);
201            }
202    
203            /**
204             * Gets an instance of the class (called via reflection).
205             *
206             * @param config The current Configuration.
207             * @param options The pattern options, may be null. If the first element is "short", only the first line of the
208             *                throwable will be formatted.
209             * @return new instance of class or null
210             */
211            public static Magenta newInstance(final Configuration config, final String[] options) {
212                return newInstance(Magenta.class, NAME, config, options);
213            }
214        }
215    
216        /**
217         * Red style pattern converter. Adds ANSI color styling to the result of the enclosed pattern.
218         */
219        @Plugin(name = Red.NAME, category = "Converter")
220        @ConverterKeys(Red.NAME)
221        public static final class Red extends AbstractStyleNameConverter {
222    
223            /** Red */
224            protected static final String NAME = "red";
225    
226            /**
227             * Constructs the converter. This constructor must be public.
228             *
229             * @param formatters The PatternFormatters to generate the text to manipulate.
230             * @param styling The styling that should encapsulate the pattern.
231             */
232            public Red(final List<PatternFormatter> formatters, final String styling) {
233                super(NAME, formatters, styling);
234            }
235    
236            /**
237             * Gets an instance of the class (called via reflection).
238             *
239             * @param config The current Configuration.
240             * @param options The pattern options, may be null. If the first element is "short", only the first line of the
241             *                throwable will be formatted.
242             * @return new instance of class or null
243             */
244            public static Red newInstance(final Configuration config, final String[] options) {
245                return newInstance(Red.class, NAME, config, options);
246            }
247        }
248    
249        /**
250         * White style pattern converter. Adds ANSI color styling to the result of the enclosed pattern.
251         */
252        @Plugin(name = White.NAME, category = "Converter")
253        @ConverterKeys(White.NAME)
254        public static final class White extends AbstractStyleNameConverter {
255    
256            /** White */
257            protected static final String NAME = "white";
258    
259            /**
260             * Constructs the converter. This constructor must be public.
261             *
262             * @param formatters The PatternFormatters to generate the text to manipulate.
263             * @param styling The styling that should encapsulate the pattern.
264             */
265            public White(final List<PatternFormatter> formatters, final String styling) {
266                super(NAME, formatters, styling);
267            }
268    
269            /**
270             * Gets an instance of the class (called via reflection).
271             *
272             * @param config The current Configuration.
273             * @param options The pattern options, may be null. If the first element is "short", only the first line of the
274             *                throwable will be formatted.
275             * @return new instance of class or null
276             */
277            public static White newInstance(final Configuration config, final String[] options) {
278                return newInstance(White.class, NAME, config, options);
279            }
280        }
281    
282        /**
283         * Yellow style pattern converter. Adds ANSI color styling to the result of the enclosed pattern.
284         */
285        @Plugin(name = Yellow.NAME, category = "Converter")
286        @ConverterKeys(Yellow.NAME)
287        public static final class Yellow extends AbstractStyleNameConverter {
288    
289            /** Yellow */
290            protected static final String NAME = "yellow";
291    
292            /**
293             * Constructs the converter. This constructor must be public.
294             *
295             * @param formatters The PatternFormatters to generate the text to manipulate.
296             * @param styling The styling that should encapsulate the pattern.
297             */
298            public Yellow(final List<PatternFormatter> formatters, final String styling) {
299                super(NAME, formatters, styling);
300            }
301    
302            /**
303             * Gets an instance of the class (called via reflection).
304             *
305             * @param config The current Configuration.
306             * @param options The pattern options, may be null. If the first element is "short", only the first line of the
307             *                throwable will be formatted.
308             * @return new instance of class or null
309             */
310            public static Yellow newInstance(final Configuration config, final String[] options) {
311                return newInstance(Yellow.class, NAME, config, options);
312            }
313        }
314    
315        /**
316         * Gets an instance of the class (called via reflection).
317         *
318         * @param config The current Configuration.
319         * @param options The pattern options, may be null. If the first element is "short", only the first line of the
320         *                throwable will be formatted.
321         * @return new instance of class or null
322         */
323        protected static <T extends AbstractStyleNameConverter> T newInstance(final Class<T> asnConverterClass,
324                                                                              final String name, final Configuration config,
325                                                                              final String[] options) {
326            final List<PatternFormatter> formatters = toPatternFormatterList(config, options);
327            if (formatters == null) {
328                return null;
329            }
330            try {
331                final Constructor<T> constructor = asnConverterClass.getConstructor(List.class, String.class);
332                return constructor.newInstance(formatters, AnsiEscape.createSequence(name));
333            } catch (final SecurityException e) {
334                LOGGER.error(e.toString(), e);
335            } catch (final NoSuchMethodException e) {
336                LOGGER.error(e.toString(), e);
337            } catch (final IllegalArgumentException e) {
338                LOGGER.error(e.toString(), e);
339            } catch (final InstantiationException e) {
340                LOGGER.error(e.toString(), e);
341            } catch (final IllegalAccessException e) {
342                LOGGER.error(e.toString(), e);
343            } catch (final InvocationTargetException e) {
344                LOGGER.error(e.toString(), e);
345            }
346            return null;
347        }
348    
349        /**
350         * Creates a list of PatternFormatter from the given configuration and options or null if no pattern is supplied.
351         *
352         * @param config A configuration.
353         * @param options pattern options.
354         * @return a list of PatternFormatter from the given configuration and options or null if no pattern is supplied.
355         */
356        private static List<PatternFormatter> toPatternFormatterList(final Configuration config, final String[] options) {
357            if (options.length == 0 || options[0] == null) {
358                LOGGER.error("No pattern supplied on style for config=" + config);
359                return null;
360            }
361            final PatternParser parser = PatternLayout.createPatternParser(config);
362            if (parser == null) {
363                LOGGER.error("No PatternParser created for config=" + config + ", options=" + Arrays.toString(options));
364                return null;
365            }
366            return parser.parse(options[0]);
367        }
368    
369        /**
370         * {@inheritDoc}
371         */
372        @Override
373        public void format(final LogEvent event, final StringBuilder toAppendTo) {
374            final StringBuilder buf = new StringBuilder();
375            for (final PatternFormatter formatter : formatters) {
376                formatter.format(event, buf);
377            }
378            if (buf.length() > 0) {
379                toAppendTo.append(style).append(buf.toString()).append(AnsiEscape.getDefaultStyle());
380            }
381        }
382    }