    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    }