    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.util.List;
    020
    021    import org.apache.logging.log4j.core.LogEvent;
    022    import org.apache.logging.log4j.core.config.Configuration;
    023    import org.apache.logging.log4j.core.config.plugins.Plugin;
    024    import org.apache.logging.log4j.core.layout.PatternLayout;
    025
    026    /**
    027     * Returns the event's rendered message in a StringBuilder.
    028     */
    029    @Plugin(name = "encode", category = PatternConverter.CATEGORY)
    030    @ConverterKeys({ "enc", "encode" })
    031    public final class EncodingPatternConverter extends LogEventPatternConverter {
    032
    033        private final List<PatternFormatter> formatters;
    034
    035        /**
    036         * Private constructor.
    037         *
    038         * @param formatters The PatternFormatters to generate the text to manipulate.
    039         */
    040        private EncodingPatternConverter(final List<PatternFormatter> formatters) {
    041            super("encode", "encode");
    042            this.formatters = formatters;
    043        }
    044
    045        /**
    046         * Obtains an instance of pattern converter.
    047         *
    048         * @param config  The Configuration.
    049         * @param options options, may be null.
    050         * @return instance of pattern converter.
    051         */
    052        public static EncodingPatternConverter newInstance(final Configuration config, final String[] options) {
    053            if (options.length != 1) {
    054                LOGGER.error("Incorrect number of options on escape. Expected 1, received " + options.length);
    055                return null;
    056            }
    057            if (options[0] == null) {
    058                LOGGER.error("No pattern supplied on escape");
    059                return null;
    060            }
    061            final PatternParser parser = PatternLayout.createPatternParser(config);
    062            final List<PatternFormatter> formatters = parser.parse(options[0]);
    063            return new EncodingPatternConverter(formatters);
    064        }
    065
    066        /**
    067         * {@inheritDoc}
    068         */
    069        @Override
    070        public void format(final LogEvent event, final StringBuilder toAppendTo) {
    071            final StringBuilder buf = new StringBuilder();
    072            for (final PatternFormatter formatter : formatters) {
    073                formatter.format(event, buf);
    074            }
    075            for (int i = 0; i < buf.length(); i++) {
    076                final char c = buf.charAt(i);
    077                switch (c) {
    078                    case '\r':
    079                        toAppendTo.append("\\r");
    080                        break;
    081                    case '\n':
    082                        toAppendTo.append("\\n");
    083                        break;
    084                    case '&':
    085                        toAppendTo.append("&amp;");
    086                        break;
    087                    case '<':
    088                        toAppendTo.append("&lt;");
    089                        break;
    090                    case '>':
    091                        toAppendTo.append("&gt;");
    092                        break;
    093                    case '"':
    094                        toAppendTo.append("&quot;");
    095                        break;
    096                    case '\'':
    097                        toAppendTo.append("&apos;");
    098                        break;
    099                    case '/':
    100                        toAppendTo.append("&#x2F;");
    101                        break;
    102                    default:
    103                        toAppendTo.append(c);
    104                        break;
    105                }
    106            }
    107        }
    108    }