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.jpa;
18  
19  import java.util.Map;
20  
21  import javax.persistence.Inheritance;
22  import javax.persistence.InheritanceType;
23  import javax.persistence.MappedSuperclass;
24  import javax.persistence.Transient;
25  
26  import org.apache.logging.log4j.Level;
27  import org.apache.logging.log4j.Marker;
28  import org.apache.logging.log4j.ThreadContext;
29  import org.apache.logging.log4j.core.LogEvent;
30  import org.apache.logging.log4j.message.Message;
31  
32  /**
33   * <p>
34   * Users of the JPA appender MUST extend this class, using JPA annotations on the concrete class and all of its
35   * accessor methods (as needed) to map them to the proper table and columns. Accessors you do not want persisted should
36   * be annotated with {@link Transient @Transient}. All accessors should call {@link #getWrappedEvent()} and delegate the
37   * call to the underlying event. Users may want to instead extend {@link BasicLogEventEntity}, which takes care of all
38   * of this for you.
39   * </p>
40   * <p>
41   * The concrete class must have two constructors: a public no-arg constructor to convince the JPA provider that it's a
42   * valid entity, and a public constructor that takes a single {@link LogEvent event} and passes it to the parent class
43   * with {@link #AbstractLogEventWrapperEntity(LogEvent) super(event)}. Furthermore, the concrete class must be annotated
44   * {@link javax.persistence.Entity @Entity} and {@link javax.persistence.Table @Table} and must implement a fully
45   * mutable ID property annotated with {@link javax.persistence.Id @Id} and
46   * {@link javax.persistence.GeneratedValue @GeneratedValue} to tell the JPA provider how to calculate an ID for new
47   * events.
48   * </p>
49   * <p>
50   * Many of the return types of {@link LogEvent} methods (e.g., {@link StackTraceElement}, {@link Message},
51   * {@link Marker}, {@link Throwable}, 
52   * {@link org.apache.logging.log4j.ThreadContext.ContextStack ThreadContext.ContextStack}, and 
53   * {@link Map Map&lt;String, String&gt}) will not be recognized by the JPA provider. In conjunction with 
54   * {@link javax.persistence.Convert @Convert}, you can use the converters in the 
55   * {@link org.apache.logging.log4j.core.appender.db.jpa.converter} package to convert these types to database columns.
56   * If you want to retrieve log events from the database, you can create a true POJO entity and also use these 
57   * converters for extracting persisted values.<br>
58   * </p>
59   * <p>
60   * The mutator methods in this class not specified in {@link LogEvent} are no-op methods, implemented to satisfy the JPA
61   * requirement that accessor methods have matching mutator methods. If you create additional accessor methods, you must
62   * likewise create matching no-op mutator methods.
63   * </p>
64   *
65   * @see BasicLogEventEntity
66   */
67  @MappedSuperclass
68  @Inheritance(strategy = InheritanceType.SINGLE_TABLE)
69  public abstract class AbstractLogEventWrapperEntity implements LogEvent {
70      private static final long serialVersionUID = 1L;
71  
72      private final LogEvent wrappedEvent;
73  
74      /**
75       * Instantiates this base class. All concrete implementations must have a constructor matching this constructor's
76       * signature. The no-argument constructor is required for a standards-compliant JPA provider to accept this as an
77       * entity.
78       */
79      @SuppressWarnings("unused")
80      protected AbstractLogEventWrapperEntity() {
81          this(new NullLogEvent());
82      }
83  
84      /**
85       * Instantiates this base class. All concrete implementations must have a constructor matching this constructor's
86       * signature. This constructor is used for wrapping this entity around a logged event.
87       *
88       * @param wrappedEvent The underlying event from which information is obtained.
89       */
90      protected AbstractLogEventWrapperEntity(final LogEvent wrappedEvent) {
91          if (wrappedEvent == null) {
92              throw new IllegalArgumentException("The wrapped event cannot be null.");
93          }
94          this.wrappedEvent = wrappedEvent;
95      }
96  
97      /**
98       * All eventual accessor methods must call this method and delegate the method call to the underlying wrapped event.
99       * Annotated {@link Transient} so as not to be included in the persisted entity.
100      *
101      * @return The underlying event from which information is obtained.
102      */
103     @Transient
104     protected final LogEvent getWrappedEvent() {
105         return this.wrappedEvent;
106     }
107 
108     /**
109      * A no-op mutator to satisfy JPA requirements, as this entity is write-only.
110      *
111      * @param level Ignored.
112      */
113     @SuppressWarnings("unused")
114     public void setLevel(final Level level) {
115         // this entity is write-only
116     }
117 
118     /**
119      * A no-op mutator to satisfy JPA requirements, as this entity is write-only.
120      *
121      * @param loggerName Ignored.
122      */
123     @SuppressWarnings("unused")
124     public void setLoggerName(final String loggerName) {
125         // this entity is write-only
126     }
127 
128     /**
129      * A no-op mutator to satisfy JPA requirements, as this entity is write-only.
130      *
131      * @param source Ignored.
132      */
133     @SuppressWarnings("unused")
134     public void setSource(final StackTraceElement source) {
135         // this entity is write-only
136     }
137 
138     /**
139      * A no-op mutator to satisfy JPA requirements, as this entity is write-only.
140      *
141      * @param message Ignored.
142      */
143     @SuppressWarnings("unused")
144     public void setMessage(final Message message) {
145         // this entity is write-only
146     }
147 
148     /**
149      * A no-op mutator to satisfy JPA requirements, as this entity is write-only.
150      *
151      * @param marker Ignored.
152      */
153     @SuppressWarnings("unused")
154     public void setMarker(final Marker marker) {
155         // this entity is write-only
156     }
157 
158     /**
159      * A no-op mutator to satisfy JPA requirements, as this entity is write-only.
160      *
161      * @param threadName Ignored.
162      */
163     @SuppressWarnings("unused")
164     public void setThreadName(final String threadName) {
165         // this entity is write-only
166     }
167 
168     /**
169      * A no-op mutator to satisfy JPA requirements, as this entity is write-only.
170      *
171      * @param millis Ignored.
172      */
173     @SuppressWarnings("unused")
174     public void setMillis(final long millis) {
175         // this entity is write-only
176     }
177 
178     /**
179      * A no-op mutator to satisfy JPA requirements, as this entity is write-only.
180      *
181      * @param throwable Ignored.
182      */
183     @SuppressWarnings("unused")
184     public void setThrown(final Throwable throwable) {
185         // this entity is write-only
186     }
187 
188     /**
189      * A no-op mutator to satisfy JPA requirements, as this entity is write-only.
190      *
191      * @param contextMap Ignored.
192      */
193     @SuppressWarnings("unused")
194     public void setContextMap(final Map<String, String> contextMap) {
195         // this entity is write-only
196     }
197 
198     /**
199      * A no-op mutator to satisfy JPA requirements, as this entity is write-only.
200      *
201      * @param contextStack Ignored.
202      */
203     @SuppressWarnings("unused")
204     public void setContextStack(final ThreadContext.ContextStack contextStack) {
205         // this entity is write-only
206     }
207 
208     /**
209      * A no-op mutator to satisfy JPA requirements, as this entity is write-only.
210      *
211      * @param fqcn Ignored.
212      */
213     @SuppressWarnings("unused")
214     public void setFQCN(final String fqcn) {
215         // this entity is write-only
216     }
217 
218     /**
219      * Indicates whether the source of the logging request is required downstream. Annotated
220      * {@link Transient @Transient} so as to not be included in the persisted entity.
221      *
222      * @return whether the source of the logging request is required downstream.
223      */
224     @Override
225     @Transient
226     public final boolean isIncludeLocation() {
227         return this.getWrappedEvent().isIncludeLocation();
228     }
229 
230     @Override
231     public final void setIncludeLocation(final boolean locationRequired) {
232         this.getWrappedEvent().setIncludeLocation(locationRequired);
233     }
234 
235     /**
236      * Indicates whether this event is the last one in a batch. Annotated {@link Transient @Transient} so as to not be
237      * included in the persisted entity.
238      *
239      * @return whether this event is the last one in a batch.
240      */
241     @Override
242     @Transient
243     public final boolean isEndOfBatch() {
244         return this.getWrappedEvent().isEndOfBatch();
245     }
246 
247     @Override
248     public final void setEndOfBatch(final boolean endOfBatch) {
249         this.getWrappedEvent().setEndOfBatch(endOfBatch);
250     }
251 
252     /**
253      * A no-op log event class to prevent {@code NullPointerException}s. O/RMs tend to create instances of entities in
254      * order to "play around" with them.
255      */
256     private static class NullLogEvent implements LogEvent {
257         private static final long serialVersionUID = 1L;
258 
259         @Override
260         public Level getLevel() {
261             return null;
262         }
263 
264         @Override
265         public String getLoggerName() {
266             return null;
267         }
268 
269         @Override
270         public StackTraceElement getSource() {
271             return null;
272         }
273 
274         @Override
275         public Message getMessage() {
276             return null;
277         }
278 
279         @Override
280         public Marker getMarker() {
281             return null;
282         }
283 
284         @Override
285         public String getThreadName() {
286             return null;
287         }
288 
289         @Override
290         public long getMillis() {
291             return 0;
292         }
293 
294         @Override
295         public Throwable getThrown() {
296             return null;
297         }
298 
299         @Override
300         public Map<String, String> getContextMap() {
301             return null;
302         }
303 
304         @Override
305         public ThreadContext.ContextStack getContextStack() {
306             return null;
307         }
308 
309         @Override
310         public String getFQCN() {
311             return null;
312         }
313 
314         @Override
315         public boolean isIncludeLocation() {
316             return false;
317         }
318 
319         @Override
320         public void setIncludeLocation(final boolean locationRequired) {
321 
322         }
323 
324         @Override
325         public boolean isEndOfBatch() {
326             return false;
327         }
328 
329         @Override
330         public void setEndOfBatch(final boolean endOfBatch) {
331 
332         }
333     }
334 }