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.logging.log4j.core.appender.db.jdbc;
018
019import org.apache.logging.log4j.Logger;
020import org.apache.logging.log4j.core.config.Configuration;
021import org.apache.logging.log4j.core.config.plugins.Plugin;
022import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
023import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
024import org.apache.logging.log4j.core.config.plugins.PluginFactory;
025import org.apache.logging.log4j.core.layout.PatternLayout;
026import org.apache.logging.log4j.core.util.Booleans;
027import org.apache.logging.log4j.status.StatusLogger;
028import org.apache.logging.log4j.util.Strings;
029
030/**
031 * A configuration element used to configure which event properties are logged to which columns in the database table.
032 */
033@Plugin(name = "Column", category = "Core", printObject = true)
034public final class ColumnConfig {
035    private static final Logger LOGGER = StatusLogger.getLogger();
036
037    private final String columnName;
038    private final PatternLayout layout;
039    private final String literalValue;
040    private final boolean eventTimestamp;
041    private final boolean unicode;
042    private final boolean clob;
043
044    private ColumnConfig(final String columnName, final PatternLayout layout, final String literalValue,
045                         final boolean eventDate, final boolean unicode, final boolean clob) {
046        this.columnName = columnName;
047        this.layout = layout;
048        this.literalValue = literalValue;
049        this.eventTimestamp = eventDate;
050        this.unicode = unicode;
051        this.clob = clob;
052    }
053
054    public String getColumnName() {
055        return this.columnName;
056    }
057
058    public PatternLayout getLayout() {
059        return this.layout;
060    }
061
062    public String getLiteralValue() {
063        return this.literalValue;
064    }
065
066    public boolean isEventTimestamp() {
067        return this.eventTimestamp;
068    }
069
070    public boolean isUnicode() {
071        return this.unicode;
072    }
073
074    public boolean isClob() {
075        return this.clob;
076    }
077
078    @Override
079    public String toString() {
080        return "{ name=" + this.columnName + ", layout=" + this.layout + ", literal=" + this.literalValue
081                + ", timestamp=" + this.eventTimestamp + " }";
082    }
083
084    /**
085     * Factory method for creating a column config within the plugin manager.
086     *
087     * @param config The configuration object
088     * @param name The name of the database column as it exists within the database table.
089     * @param pattern The {@link PatternLayout} pattern to insert in this column. Mutually exclusive with
090     *                {@code literalValue!=null} and {@code eventTimestamp=true}
091     * @param literalValue The literal value to insert into the column as-is without any quoting or escaping. Mutually
092     *                     exclusive with {@code pattern!=null} and {@code eventTimestamp=true}.
093     * @param eventTimestamp If {@code "true"}, indicates that this column is a date-time column in which the event
094     *                       timestamp should be inserted. Mutually exclusive with {@code pattern!=null} and
095     *                       {@code literalValue!=null}.
096     * @param unicode If {@code "true"}, indicates that the column is a Unicode String.
097     * @param clob If {@code "true"}, indicates that the column is a character LOB (CLOB).
098     * @return the created column config.
099     */
100    @PluginFactory
101    public static ColumnConfig createColumnConfig(
102            @PluginConfiguration final Configuration config,
103            @PluginAttribute("name") final String name,
104            @PluginAttribute("pattern") final String pattern,
105            @PluginAttribute("literal") final String literalValue,
106            @PluginAttribute("isEventTimestamp") final String eventTimestamp,
107            @PluginAttribute("isUnicode") final String unicode,
108            @PluginAttribute("isClob") final String clob) {
109        if (Strings.isEmpty(name)) {
110            LOGGER.error("The column config is not valid because it does not contain a column name.");
111            return null;
112        }
113
114        final boolean isPattern = Strings.isNotEmpty(pattern);
115        final boolean isLiteralValue = Strings.isNotEmpty(literalValue);
116        final boolean isEventTimestamp = Boolean.parseBoolean(eventTimestamp);
117        final boolean isUnicode = Booleans.parseBoolean(unicode, true);
118        final boolean isClob = Boolean.parseBoolean(clob);
119
120        if ((isPattern && isLiteralValue) || (isPattern && isEventTimestamp) || (isLiteralValue && isEventTimestamp)) {
121            LOGGER.error("The pattern, literal, and isEventTimestamp attributes are mutually exclusive.");
122            return null;
123        }
124
125        if (isEventTimestamp) {
126            return new ColumnConfig(name, null, null, true, false, false);
127        }
128        if (isLiteralValue) {
129            return new ColumnConfig(name, null, literalValue, false, false, false);
130        }
131        if (isPattern) {
132            final PatternLayout layout =
133                PatternLayout.newBuilder()
134                    .withPattern(pattern)
135                    .withConfiguration(config)
136                    .withAlwaysWriteExceptions(false)
137                    .build();
138            return new ColumnConfig(name, layout, null, false, isUnicode, isClob);
139        }
140
141        LOGGER.error("To configure a column you must specify a pattern or literal or set isEventDate to true.");
142        return null;
143    }
144}