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.jpa; 018 019 import java.util.Map; 020 import javax.persistence.MappedSuperclass; 021 import javax.persistence.Transient; 022 023 import org.apache.logging.log4j.Level; 024 import org.apache.logging.log4j.Marker; 025 import org.apache.logging.log4j.ThreadContext; 026 import org.apache.logging.log4j.core.LogEvent; 027 import org.apache.logging.log4j.message.Message; 028 029 /** 030 * Users of the JPA appender MUST extend this class, using JPA annotations on the concrete class and all of its 031 * accessor methods (as needed) to map them to the proper table and columns. Accessors you do not want persisted should 032 * be annotated with {@link Transient @Transient}. All accessors should call {@link #getWrappedEvent()} and delegate the 033 * call to the underlying event. Users may want to instead extend {@link BasicLogEventEntity}, which takes care of all 034 * of this for you.<br> 035 * <br> 036 * The concrete class must have two constructors: a public no-arg constructor to convince the JPA provider that it's a 037 * valid entity, and a public constructor that takes a single {@link LogEvent event} and passes it to the parent class 038 * with {@link #AbstractLogEventWrapperEntity(LogEvent) super(event)}. Furthermore, the concrete class must be annotated 039 * {@link javax.persistence.Entity @Entity} and {@link javax.persistence.Table @Table} and must implement a fully 040 * mutable ID property annotated with {@link javax.persistence.Id @Id} and 041 * {@link javax.persistence.GeneratedValue @GeneratedValue} to tell the JPA provider how to calculate an ID for new 042 * events.<br> 043 * <br> 044 * Many of the return types of {@link LogEvent} methods (e.g., {@link StackTraceElement}, {@link Message}, 045 * {@link Marker}, {@link Throwable}, {@link ThreadContext.ContextStack}, and {@link Map Map<String, String>}) will 046 * not be recognized by the JPA provider. In conjunction with {@link javax.persistence.Convert @Convert}, you can use 047 * the converters in the {@link org.apache.logging.log4j.core.appender.db.jpa.converter} package to convert these 048 * types to database columns. If you want to retrieve log events from the database, you can create a true POJO entity 049 * and also use these converters for extracting persisted values.<br> 050 * <br> 051 * The mutator methods in this class not specified in {@link LogEvent} are no-op methods, implemented to satisfy the JPA 052 * requirement that accessor methods have matching mutator methods. If you create additional accessor methods, you must 053 * likewise create matching no-op mutator methods. 054 * 055 * @see BasicLogEventEntity 056 */ 057 @MappedSuperclass 058 public abstract class AbstractLogEventWrapperEntity implements LogEvent { 059 private static final long serialVersionUID = 1L; 060 061 private final LogEvent wrappedEvent; 062 063 /** 064 * Instantiates this base class. All concrete implementations must have a constructor matching this constructor's 065 * signature. The no-argument constructor is required for a standards-compliant JPA provider to accept this as an 066 * entity. 067 */ 068 @SuppressWarnings("unused") 069 protected AbstractLogEventWrapperEntity() { 070 this(null); 071 } 072 073 /** 074 * Instantiates this base class. All concrete implementations must have a constructor matching this constructor's 075 * signature. This constructor is used for wrapping this entity around a logged event. 076 * 077 * @param wrappedEvent The underlying event from which information is obtained. 078 */ 079 protected AbstractLogEventWrapperEntity(final LogEvent wrappedEvent) { 080 this.wrappedEvent = wrappedEvent; 081 } 082 083 /** 084 * All eventual accessor methods must call this method and delegate the method call to the underlying wrapped event. 085 * Annotated {@link @Transient} so as not to be included in the persisted entity. 086 * 087 * @return The underlying event from which information is obtained. 088 */ 089 @Transient 090 protected final LogEvent getWrappedEvent() { 091 return this.wrappedEvent; 092 } 093 094 /** 095 * A no-op mutator to satisfy JPA requirements, as this entity is write-only. 096 * 097 * @param level Ignored. 098 */ 099 @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 }