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    }