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; 018 019import java.util.Date; 020 021import org.apache.logging.log4j.Logger; 022import org.apache.logging.log4j.core.Core; 023import org.apache.logging.log4j.core.StringLayout; 024import org.apache.logging.log4j.core.config.Configuration; 025import org.apache.logging.log4j.core.config.plugins.Plugin; 026import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute; 027import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory; 028import org.apache.logging.log4j.core.config.plugins.PluginConfiguration; 029import org.apache.logging.log4j.core.config.plugins.PluginElement; 030import org.apache.logging.log4j.core.config.plugins.validation.constraints.Required; 031import org.apache.logging.log4j.core.layout.PatternLayout; 032import org.apache.logging.log4j.spi.ThreadContextMap; 033import org.apache.logging.log4j.spi.ThreadContextStack; 034import org.apache.logging.log4j.status.StatusLogger; 035import org.apache.logging.log4j.util.ReadOnlyStringMap; 036 037/** 038 * A configuration element for specifying a database column name mapping. 039 * 040 * @since 2.8 041 */ 042@Plugin(name = "ColumnMapping", category = Core.CATEGORY_NAME, printObject = true) 043public class ColumnMapping { 044 045 private static final Logger LOGGER = StatusLogger.getLogger(); 046 047 private final String name; 048 private final StringLayout layout; 049 private final String literalValue; 050 private final Class<?> type; 051 052 private ColumnMapping(final String name, final StringLayout layout, final String literalValue, final Class<?> type) { 053 this.name = name; 054 this.layout = layout; 055 this.literalValue = literalValue; 056 this.type = type; 057 } 058 059 public String getName() { 060 return name; 061 } 062 063 public StringLayout getLayout() { 064 return layout; 065 } 066 067 public String getLiteralValue() { 068 return literalValue; 069 } 070 071 public Class<?> getType() { 072 return type; 073 } 074 075 @PluginBuilderFactory 076 public static Builder newBuilder() { 077 return new Builder(); 078 } 079 080 public static class Builder implements org.apache.logging.log4j.core.util.Builder<ColumnMapping> { 081 082 @PluginBuilderAttribute 083 @Required(message = "No column name provided") 084 private String name; 085 086 @PluginElement("Layout") 087 private StringLayout layout; 088 089 @PluginBuilderAttribute 090 private String pattern; 091 092 @PluginBuilderAttribute 093 private String literal; 094 095 @PluginBuilderAttribute 096 @Required(message = "No conversion type provided") 097 private Class<?> type = String.class; 098 099 @PluginConfiguration 100 private Configuration configuration; 101 102 /** 103 * Column name. 104 */ 105 public Builder setName(final String name) { 106 this.name = name; 107 return this; 108 } 109 110 /** 111 * Layout of value to write to database (before type conversion). Not applicable if {@link #setType(Class)} is 112 * a {@link ReadOnlyStringMap}, {@link ThreadContextMap}, or {@link ThreadContextStack}. 113 */ 114 public Builder setLayout(final StringLayout layout) { 115 this.layout = layout; 116 return this; 117 } 118 119 /** 120 * Pattern to use as a {@link PatternLayout}. Convenient shorthand for {@link #setLayout(StringLayout)} with a 121 * PatternLayout. 122 */ 123 public Builder setPattern(final String pattern) { 124 this.pattern = pattern; 125 return this; 126 } 127 128 /** 129 * Literal value to use for populating a column. This is generally useful for functions, stored procedures, 130 * etc. No escaping will be done on this value. 131 */ 132 public Builder setLiteral(final String literal) { 133 this.literal = literal; 134 return this; 135 } 136 137 /** 138 * Class to convert value to before storing in database. If the type is compatible with {@link ThreadContextMap} or 139 * {@link ReadOnlyStringMap}, then the MDC will be used. If the type is compatible with {@link ThreadContextStack}, 140 * then the NDC will be used. If the type is compatible with {@link Date}, then the event timestamp will be used. 141 */ 142 public Builder setType(final Class<?> type) { 143 this.type = type; 144 return this; 145 } 146 147 public Builder setConfiguration(final Configuration configuration) { 148 this.configuration = configuration; 149 return this; 150 } 151 152 @Override 153 public ColumnMapping build() { 154 if (pattern != null) { 155 layout = PatternLayout.newBuilder() 156 .withPattern(pattern) 157 .withConfiguration(configuration) 158 .build(); 159 } 160 if (!(layout != null 161 || literal != null 162 || Date.class.isAssignableFrom(type) 163 || ReadOnlyStringMap.class.isAssignableFrom(type) 164 || ThreadContextMap.class.isAssignableFrom(type) 165 || ThreadContextStack.class.isAssignableFrom(type))) { 166 LOGGER.error("No layout or literal value specified and type ({}) is not compatible with " + 167 "ThreadContextMap, ThreadContextStack, or java.util.Date", type); 168 return null; 169 } 170 return new ColumnMapping(name, layout, literal, type); 171 } 172 } 173}