    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.appender.db.jdbc;
    018
    019    import org.apache.logging.log4j.Logger;
    020    import org.apache.logging.log4j.core.config.Configuration;
    021    import org.apache.logging.log4j.core.config.plugins.Plugin;
    022    import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
    023    import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
    024    import org.apache.logging.log4j.core.config.plugins.PluginFactory;
    025    import org.apache.logging.log4j.core.layout.PatternLayout;
    026    import org.apache.logging.log4j.core.util.Booleans;
    027    import org.apache.logging.log4j.status.StatusLogger;
    028    import 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)
    034    public 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    }