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 import javax.persistence.MappedSuperclass; 21 import javax.persistence.Transient; 22 23 import org.apache.logging.log4j.Level; 24 import org.apache.logging.log4j.Marker; 25 import org.apache.logging.log4j.ThreadContext; 26 import org.apache.logging.log4j.core.LogEvent; 27 import org.apache.logging.log4j.message.Message; 28 29 /** 30 * Users of the JPA appender MUST extend this class, using JPA annotations on the concrete class and all of its 31 * accessor methods (as needed) to map them to the proper table and columns. Accessors you do not want persisted should 32 * be annotated with {@link Transient @Transient}. All accessors should call {@link #getWrappedEvent()} and delegate the 33 * call to the underlying event. Users may want to instead extend {@link BasicLogEventEntity}, which takes care of all 34 * of this for you.<br> 35 * <br> 36 * The concrete class must have two constructors: a public no-arg constructor to convince the JPA provider that it's a 37 * valid entity, and a public constructor that takes a single {@link LogEvent event} and passes it to the parent class 38 * with {@link #AbstractLogEventWrapperEntity(LogEvent) super(event)}. Furthermore, the concrete class must be annotated 39 * {@link javax.persistence.Entity @Entity} and {@link javax.persistence.Table @Table} and must implement a fully 40 * mutable ID property annotated with {@link javax.persistence.Id @Id} and 41 * {@link javax.persistence.GeneratedValue @GeneratedValue} to tell the JPA provider how to calculate an ID for new 42 * events.<br> 43 * <br> 44 * Many of the return types of {@link LogEvent} methods (e.g., {@link StackTraceElement}, {@link Message}, 45 * {@link Marker}, {@link Throwable}, {@link ThreadContext.ContextStack}, and {@link Map Map<String, String>}) will 46 * not be recognized by the JPA provider. In conjunction with {@link javax.persistence.Convert @Convert}, you can use 47 * the converters in the {@link org.apache.logging.log4j.core.appender.db.jpa.converter} package to convert these 48 * types to database columns. If you want to retrieve log events from the database, you can create a true POJO entity 49 * and also use these converters for extracting persisted values.<br> 50 * <br> 51 * The mutator methods in this class not specified in {@link LogEvent} are no-op methods, implemented to satisfy the JPA 52 * requirement that accessor methods have matching mutator methods. If you create additional accessor methods, you must 53 * likewise create matching no-op mutator methods. 54 * 55 * @see BasicLogEventEntity 56 */ 57 @MappedSuperclass 58 public abstract class AbstractLogEventWrapperEntity implements LogEvent { 59 private static final long serialVersionUID = 1L; 60 61 private final LogEvent wrappedEvent; 62 63 /** 64 * Instantiates this base class. All concrete implementations must have a constructor matching this constructor's 65 * signature. The no-argument constructor is required for a standards-compliant JPA provider to accept this as an 66 * entity. 67 */ 68 @SuppressWarnings("unused") 69 protected AbstractLogEventWrapperEntity() { 70 this(null); 71 } 72 73 /** 74 * Instantiates this base class. All concrete implementations must have a constructor matching this constructor's 75 * signature. This constructor is used for wrapping this entity around a logged event. 76 * 77 * @param wrappedEvent The underlying event from which information is obtained. 78 */ 79 protected AbstractLogEventWrapperEntity(final LogEvent wrappedEvent) { 80 this.wrappedEvent = wrappedEvent; 81 } 82 83 /** 84 * All eventual accessor methods must call this method and delegate the method call to the underlying wrapped event. 85 * Annotated {@link @Transient} so as not to be included in the persisted entity. 86 * 87 * @return The underlying event from which information is obtained. 88 */ 89 @Transient 90 protected final LogEvent getWrappedEvent() { 91 return this.wrappedEvent; 92 } 93 94 /** 95 * A no-op mutator to satisfy JPA requirements, as this entity is write-only. 96 * 97 * @param level Ignored. 98 */ 99 @SuppressWarnings("unused") 100 public void setLevel(final Level level) { 101 // this entity is write-only 102 } 103 104 /** 105 * A no-op mutator to satisfy JPA requirements, as this entity is write-only. 106 * 107 * @param loggerName Ignored. 108 */ 109 @SuppressWarnings("unused") 110 public void setLoggerName(final String loggerName) { 111 // this entity is write-only 112 } 113 114 /** 115 * A no-op mutator to satisfy JPA requirements, as this entity is write-only. 116 * 117 * @param source Ignored. 118 */ 119 @SuppressWarnings("unused") 120 public void setSource(final StackTraceElement source) { 121 // this entity is write-only 122 } 123 124 /** 125 * A no-op mutator to satisfy JPA requirements, as this entity is write-only. 126 * 127 * @param message Ignored. 128 */ 129 @SuppressWarnings("unused") 130 public void setMessage(final Message message) { 131 // this entity is write-only 132 } 133 134 /** 135 * A no-op mutator to satisfy JPA requirements, as this entity is write-only. 136 * 137 * @param marker Ignored. 138 */ 139 @SuppressWarnings("unused") 140 public void setMarker(final Marker marker) { 141 // this entity is write-only 142 } 143 144 /** 145 * A no-op mutator to satisfy JPA requirements, as this entity is write-only. 146 * 147 * @param threadName Ignored. 148 */ 149 @SuppressWarnings("unused") 150 public void setThreadName(final String threadName) { 151 // this entity is write-only 152 } 153 154 /** 155 * A no-op mutator to satisfy JPA requirements, as this entity is write-only. 156 * 157 * @param millis Ignored. 158 */ 159 @SuppressWarnings("unused") 160 public void setMillis(final long millis) { 161 // this entity is write-only 162 } 163 164 /** 165 * A no-op mutator to satisfy JPA requirements, as this entity is write-only. 166 * 167 * @param throwable Ignored. 168 */ 169 @SuppressWarnings("unused") 170 public void setThrown(final Throwable throwable) { 171 // this entity is write-only 172 } 173 174 /** 175 * A no-op mutator to satisfy JPA requirements, as this entity is write-only. 176 * 177 * @param contextMap Ignored. 178 */ 179 @SuppressWarnings("unused") 180 public void setContextMap(final Map<String, String> contextMap) { 181 // this entity is write-only 182 } 183 184 /** 185 * A no-op mutator to satisfy JPA requirements, as this entity is write-only. 186 * 187 * @param contextStack Ignored. 188 */ 189 @SuppressWarnings("unused") 190 public void setContextStack(final ThreadContext.ContextStack contextStack) { 191 // this entity is write-only 192 } 193 194 /** 195 * A no-op mutator to satisfy JPA requirements, as this entity is write-only. 196 * 197 * @param fqcn Ignored. 198 */ 199 @SuppressWarnings("unused") 200 public void setFQCN(final String fqcn) { 201 // this entity is write-only 202 } 203 204 /** 205 * Indicates whether the source of the logging request is required downstream. Annotated {@link Transient @Transient} so as 206 * not to be included in the persisted entity. 207 * 208 * @return whether the source of the logging request is required downstream. 209 */ 210 @Override 211 @Transient 212 public final boolean isIncludeLocation() { 213 return this.getWrappedEvent().isIncludeLocation(); 214 } 215 216 @Override 217 public final void setIncludeLocation(final boolean locationRequired) { 218 this.getWrappedEvent().setIncludeLocation(locationRequired); 219 } 220 221 /** 222 * Indicates whether this event is the last one in a batch. Annotated {@link Transient @Transient} so as not to be included 223 * in the persisted entity. 224 * 225 * @return whether this event is the last one in a batch. 226 */ 227 @Override 228 @Transient 229 public final boolean isEndOfBatch() { 230 return this.getWrappedEvent().isEndOfBatch(); 231 } 232 233 @Override 234 public final void setEndOfBatch(final boolean endOfBatch) { 235 this.getWrappedEvent().setEndOfBatch(endOfBatch); 236 } 237 }