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 */
017package org.apache.log4j.builders.layout;
018
019import org.apache.log4j.Layout;
020import org.apache.log4j.bridge.LayoutWrapper;
021import org.apache.log4j.builders.AbstractBuilder;
022import org.apache.log4j.config.Log4j1Configuration;
023import org.apache.log4j.config.PropertiesConfiguration;
024import org.apache.log4j.xml.XmlConfiguration;
025import org.apache.logging.log4j.Logger;
026import org.apache.logging.log4j.core.config.plugins.Plugin;
027import org.apache.logging.log4j.core.config.plugins.PluginAliases;
028import org.apache.logging.log4j.core.layout.PatternLayout;
029import org.apache.logging.log4j.status.StatusLogger;
030import org.w3c.dom.Element;
031import org.w3c.dom.Node;
032import org.w3c.dom.NodeList;
033
034import java.util.Properties;
035
036import static org.apache.log4j.builders.BuilderManager.CATEGORY;
037import static org.apache.log4j.xml.XmlConfiguration.PARAM_TAG;
038
039/**
040 * Build a Pattern Layout
041 */
042@Plugin(name = "org.apache.log4j.PatternLayout", category = CATEGORY)
043@PluginAliases("org.apache.log4j.EnhancedPatternLayout")
044public class PatternLayoutBuilder extends AbstractBuilder implements LayoutBuilder {
045
046    private static final Logger LOGGER = StatusLogger.getLogger();
047    private static final String PATTERN = "ConversionPattern";
048
049    public PatternLayoutBuilder() {
050    }
051
052    public PatternLayoutBuilder(String prefix, Properties props) {
053        super(prefix, props);
054    }
055
056    @Override
057    public Layout parseLayout(final Element layoutElement, final XmlConfiguration config) {
058        NodeList params = layoutElement.getElementsByTagName("param");
059        final int length = params.getLength();
060        String pattern = null;
061        for (int index = 0; index < length; ++ index) {
062            Node currentNode = params.item(index);
063            if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
064                Element currentElement = (Element) currentNode;
065                if (currentElement.getTagName().equals(PARAM_TAG)) {
066                    if (PATTERN.equalsIgnoreCase(currentElement.getAttribute("name"))) {
067                        pattern = currentElement.getAttribute("value");
068                        break;
069                    }
070                }
071            }
072        }
073        return createLayout(pattern, config);
074    }
075
076    @Override
077    public Layout parseLayout(final PropertiesConfiguration config) {
078        String pattern = getProperty(PATTERN);
079        return createLayout(pattern, config);
080    }
081
082    private Layout createLayout(String pattern, final Log4j1Configuration config) {
083        if (pattern == null) {
084            LOGGER.info("No pattern provided for pattern layout, using default pattern");
085            pattern = PatternLayout.DEFAULT_CONVERSION_PATTERN;
086        }
087        return new LayoutWrapper(PatternLayout.newBuilder()
088                .withPattern(pattern
089                        // Log4j 2's %x (NDC) is not compatible with Log4j 1's
090                        // %x
091                        // Log4j 1: "foo bar baz"
092                        // Log4j 2: "[foo, bar, baz]"
093                        // Use %ndc to get the Log4j 1 format
094                        .replace("%x", "%ndc")
095
096                        // Log4j 2's %X (MDC) is not compatible with Log4j 1's
097                        // %X
098                        // Log4j 1: "{{foo,bar}{hoo,boo}}"
099                        // Log4j 2: "{foo=bar,hoo=boo}"
100                        // Use %properties to get the Log4j 1 format
101                        .replace("%X", "%properties"))
102                .withConfiguration(config)
103                .build());
104    }
105}