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 static org.apache.log4j.builders.BuilderManager.CATEGORY;
020import static org.apache.log4j.xml.XmlConfiguration.NAME_ATTR;
021import static org.apache.log4j.xml.XmlConfiguration.PARAM_TAG;
022import static org.apache.log4j.xml.XmlConfiguration.VALUE_ATTR;
023import static org.apache.log4j.xml.XmlConfiguration.forEachElement;
024
025import java.util.Properties;
026import java.util.concurrent.atomic.AtomicBoolean;
027import java.util.concurrent.atomic.AtomicReference;
028
029import org.apache.log4j.Layout;
030import org.apache.log4j.bridge.LayoutWrapper;
031import org.apache.log4j.builders.AbstractBuilder;
032import org.apache.log4j.config.Log4j1Configuration;
033import org.apache.log4j.config.PropertiesConfiguration;
034import org.apache.log4j.xml.XmlConfiguration;
035import org.apache.logging.log4j.Logger;
036import org.apache.logging.log4j.core.config.plugins.Plugin;
037import org.apache.logging.log4j.core.layout.PatternLayout;
038import org.apache.logging.log4j.status.StatusLogger;
039import org.w3c.dom.Element;
040
041/**
042 * Build a Pattern Layout
043 */
044@Plugin(name = "org.apache.log4j.TTCCLayout", category = CATEGORY)
045public class TTCCLayoutBuilder extends AbstractBuilder implements LayoutBuilder {
046
047    private static final Logger LOGGER = StatusLogger.getLogger();
048
049    private static final String THREAD_PRINTING_PARAM = "ThreadPrinting";
050    private static final String CATEGORY_PREFIXING_PARAM = "CategoryPrefixing";
051    private static final String CONTEXT_PRINTING_PARAM = "ContextPrinting";
052    private static final String DATE_FORMAT_PARAM = "DateFormat";
053    private static final String TIMEZONE_FORMAT = "TimeZone";
054
055    public TTCCLayoutBuilder() {
056    }
057
058    public TTCCLayoutBuilder(String prefix, Properties props) {
059        super(prefix, props);
060    }
061
062    @Override
063    public Layout parseLayout(Element layoutElement, XmlConfiguration config) {
064        final AtomicBoolean threadPrinting = new AtomicBoolean();
065        final AtomicBoolean categoryPrefixing = new AtomicBoolean();
066        final AtomicBoolean contextPrinting = new AtomicBoolean();
067        final AtomicReference<String> dateFormat = new AtomicReference<>();
068        final AtomicReference<String> timezone = new AtomicReference<>();
069        forEachElement(layoutElement.getElementsByTagName("param"), currentElement -> {
070            if (currentElement.getTagName().equals(PARAM_TAG)) {
071                switch (currentElement.getAttribute(NAME_ATTR)) {
072                    case THREAD_PRINTING_PARAM:
073                        threadPrinting.set(Boolean.parseBoolean(currentElement.getAttribute(VALUE_ATTR)));
074                        break;
075                    case CATEGORY_PREFIXING_PARAM:
076                        categoryPrefixing.set(Boolean.parseBoolean(currentElement.getAttribute(VALUE_ATTR)));
077                        break;
078                    case CONTEXT_PRINTING_PARAM:
079                        contextPrinting.set(Boolean.parseBoolean(currentElement.getAttribute(VALUE_ATTR)));
080                        break;
081                    case DATE_FORMAT_PARAM:
082                        dateFormat.set(currentElement.getAttribute(VALUE_ATTR));
083                        break;
084                    case TIMEZONE_FORMAT:
085                        timezone.set(currentElement.getAttribute(VALUE_ATTR));
086                        break;
087                }
088            }
089        });
090        return createLayout(threadPrinting.get(), categoryPrefixing.get(), contextPrinting.get(),
091                dateFormat.get(), timezone.get(), config);
092    }
093
094    @Override
095    public Layout parseLayout(PropertiesConfiguration config) {
096        boolean threadPrinting = getBooleanProperty(THREAD_PRINTING_PARAM);
097        boolean categoryPrefixing = getBooleanProperty(CATEGORY_PREFIXING_PARAM);
098        boolean contextPrinting = getBooleanProperty(CONTEXT_PRINTING_PARAM);
099        String dateFormat = getProperty(DATE_FORMAT_PARAM);
100        String timezone = getProperty(TIMEZONE_FORMAT);
101
102        return createLayout(threadPrinting, categoryPrefixing, contextPrinting,
103                dateFormat, timezone, config);
104    }
105
106    private Layout createLayout(boolean threadPrinting, boolean categoryPrefixing, boolean contextPrinting,
107            String dateFormat, String timezone, Log4j1Configuration config) {
108        StringBuilder sb = new StringBuilder();
109        if (dateFormat != null) {
110            if (RELATIVE.equalsIgnoreCase(dateFormat)) {
111                sb.append("%r ");
112            } else {
113                sb.append("%d{").append(dateFormat).append("}");
114                if (timezone != null) {
115                    sb.append("{").append(timezone).append("}");
116                }
117                sb.append(" ");
118            }
119        }
120        if (threadPrinting) {
121            sb.append("[%t] ");
122        }
123        sb.append("%p ");
124        if (categoryPrefixing) {
125            sb.append("%c ");
126        }
127        if (contextPrinting) {
128            sb.append("%notEmpty{%ndc }");
129        }
130        sb.append("- %m%n");
131        return new LayoutWrapper(PatternLayout.newBuilder()
132                .withPattern(sb.toString())
133                .withConfiguration(config)
134                .build());
135    }
136}