View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache license, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License. You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the license for the specific language governing permissions and
15   * limitations under the license.
16   */
17  package org.apache.logging.log4j.core.appender.db;
18  
19  import java.util.Date;
20  
21  import org.apache.logging.log4j.Logger;
22  import org.apache.logging.log4j.core.Core;
23  import org.apache.logging.log4j.core.StringLayout;
24  import org.apache.logging.log4j.core.config.Configuration;
25  import org.apache.logging.log4j.core.config.plugins.Plugin;
26  import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
27  import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
28  import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
29  import org.apache.logging.log4j.core.config.plugins.PluginElement;
30  import org.apache.logging.log4j.core.config.plugins.validation.constraints.Required;
31  import org.apache.logging.log4j.core.layout.PatternLayout;
32  import org.apache.logging.log4j.spi.ThreadContextMap;
33  import org.apache.logging.log4j.spi.ThreadContextStack;
34  import org.apache.logging.log4j.status.StatusLogger;
35  import org.apache.logging.log4j.util.ReadOnlyStringMap;
36  
37  /**
38   * A configuration element for specifying a database column name mapping.
39   *
40   * @since 2.8
41   */
42  @Plugin(name = "ColumnMapping", category = Core.CATEGORY_NAME, printObject = true)
43  public class ColumnMapping {
44  
45      /**
46       * Builder for {@link ColumnMapping}.
47       */
48      public static class Builder implements org.apache.logging.log4j.core.util.Builder<ColumnMapping> {
49  
50          @PluginConfiguration
51          private Configuration configuration;
52  
53          @PluginElement("Layout")
54          private StringLayout layout;
55  
56          @PluginBuilderAttribute
57          private String literal;
58  
59          @PluginBuilderAttribute
60          @Required(message = "No column name provided")
61          private String name;
62  
63          @PluginBuilderAttribute
64          private String parameter;
65  
66          @PluginBuilderAttribute
67          private String pattern;
68  
69          @PluginBuilderAttribute
70          private String source;
71  
72          @PluginBuilderAttribute
73          @Required(message = "No conversion type provided")
74          private Class<?> type = String.class;
75  
76          @Override
77          public ColumnMapping build() {
78              if (pattern != null) {
79                  layout = PatternLayout.newBuilder()
80                      .withPattern(pattern)
81                      .withConfiguration(configuration)
82                      .build();
83              }
84              if (!(layout == null
85                  || literal == null
86                  || Date.class.isAssignableFrom(type)
87                  || ReadOnlyStringMap.class.isAssignableFrom(type)
88                  || ThreadContextMap.class.isAssignableFrom(type)
89                  || ThreadContextStack.class.isAssignableFrom(type))) {
90                  LOGGER.error("No 'layout' or 'literal' value specified and type ({}) is not compatible with ThreadContextMap, ThreadContextStack, or java.util.Date for the mapping", type, this);
91                  return null;
92              }
93              if (literal != null && parameter != null) {
94                  LOGGER.error("Only one of 'literal' or 'parameter' can be set on the column mapping {}", this);
95                  return null;
96              }
97              return new ColumnMapping(name, source, layout, literal, parameter, type);
98          }
99  
100         public Builder setConfiguration(final Configuration configuration) {
101             this.configuration = configuration;
102             return this;
103         }
104 
105         /**
106          * Layout of value to write to database (before type conversion). Not applicable if {@link #setType(Class)} is
107          * a {@link ReadOnlyStringMap}, {@link ThreadContextMap}, or {@link ThreadContextStack}.
108          * 
109          * @return this. 
110          */
111         public Builder setLayout(final StringLayout layout) {
112             this.layout = layout;
113             return this;
114         }
115 
116         /**
117          * Literal value to use for populating a column. This is generally useful for functions, stored procedures,
118          * etc. No escaping will be done on this value.
119          * 
120          * @return this. 
121          */
122         public Builder setLiteral(final String literal) {
123             this.literal = literal;
124             return this;
125         }
126 
127         /**
128          * Column name.
129          * 
130          * @return this. 
131          */
132         public Builder setName(final String name) {
133             this.name = name;
134             return this;
135         }
136 
137         /**
138          * Parameter value to use for populating a column, MUST contain a single parameter marker '?'. This is generally useful for functions, stored procedures,
139          * etc. No escaping will be done on this value.
140          * 
141          * @return this. 
142          */
143         public Builder setParameter(final String parameter) {
144             this.parameter= parameter;
145             return this;
146         }
147 
148         /**
149          * Pattern to use as a {@link PatternLayout}. Convenient shorthand for {@link #setLayout(StringLayout)} with a
150          * PatternLayout.
151          * 
152          * @return this. 
153          */
154         public Builder setPattern(final String pattern) {
155             this.pattern = pattern;
156             return this;
157         }
158 
159         /**
160          * Source name. Useful when combined with a {@link org.apache.logging.log4j.message.MapMessage} depending on the
161          * appender.
162          * 
163          * @return this.
164          */
165         public Builder setSource(final String source) {
166             this.source = source;
167             return this;
168         }
169 
170         /**
171          * Class to convert value to before storing in database. If the type is compatible with {@link ThreadContextMap} or
172          * {@link ReadOnlyStringMap}, then the MDC will be used. If the type is compatible with {@link ThreadContextStack},
173          * then the NDC will be used. If the type is compatible with {@link Date}, then the event timestamp will be used.
174          * 
175          * @return this. 
176          */
177         public Builder setType(final Class<?> type) {
178             this.type = type;
179             return this;
180         }
181 
182         @Override
183         public String toString() {
184             return "Builder [name=" + name + ", source=" + source + ", literal=" + literal + ", parameter=" + parameter
185                     + ", pattern=" + pattern + ", type=" + type + ", layout=" + layout + "]";
186         }
187     }
188 
189     private static final Logger LOGGER = StatusLogger.getLogger();
190     @PluginBuilderFactory
191     public static Builder newBuilder() {
192         return new Builder();
193     }
194     
195     private final StringLayout layout;
196     private final String literalValue;
197     private final String name;
198     private final String parameter;
199     private final String source;
200     private final Class<?> type;
201 
202     private ColumnMapping(final String name, final String source, final StringLayout layout, final String literalValue, final String parameter, final Class<?> type) {
203         this.name = name;
204         this.source = source;
205         this.layout = layout;
206         this.literalValue = literalValue;
207         this.parameter = parameter;
208         this.type = type;
209     }
210 
211     public StringLayout getLayout() {
212         return layout;
213     }
214 
215     public String getLiteralValue() {
216         return literalValue;
217     }
218 
219     public String getName() {
220         return name;
221     }
222 
223     public String getParameter() {
224         return parameter;
225     }
226 
227     public String getSource() {
228         return source;
229     }
230 
231     public Class<?> getType() {
232         return type;
233     }
234 
235     @Override
236     public String toString() {
237         return "ColumnMapping [name=" + name + ", source=" + source + ", literalValue=" + literalValue + ", parameter="
238                 + parameter + ", type=" + type + ", layout=" + layout + "]";
239     }
240 
241 }