Return-Path: X-Original-To: apmail-logging-commits-archive@minotaur.apache.org Delivered-To: apmail-logging-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id BC6221165A for ; Sun, 12 May 2013 22:52:37 +0000 (UTC) Received: (qmail 26218 invoked by uid 500); 12 May 2013 22:52:37 -0000 Delivered-To: apmail-logging-commits-archive@logging.apache.org Received: (qmail 26185 invoked by uid 500); 12 May 2013 22:52:37 -0000 Mailing-List: contact commits-help@logging.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@logging.apache.org Delivered-To: mailing list commits@logging.apache.org Received: (qmail 26178 invoked by uid 99); 12 May 2013 22:52:37 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 12 May 2013 22:52:37 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 12 May 2013 22:52:32 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 8386F2388847; Sun, 12 May 2013 22:52:12 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1481664 [1/2] - in /logging/log4j/log4j2/trunk: ./ core/ core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/ core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ core/src/test/java/org/apache/logging/lo... Date: Sun, 12 May 2013 22:52:11 -0000 To: commits@logging.apache.org From: nickwilliams@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20130512225212.8386F2388847@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: nickwilliams Date: Sun May 12 22:52:10 2013 New Revision: 1481664 URL: http://svn.apache.org/r1481664 Log: Updating JPAAppender to use JPA 2.1 instead, test with Hibernate 4.3 Added: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/LogEventEntity.java logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextMapAttributeConverter.java logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextMapJsonAttributeConverter.java logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextStackAttributeConverter.java logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextStackJsonAttributeConverter.java logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/MarkerAttributeConverter.java logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/MessageAttributeConverter.java logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/StackTraceElementAttributeConverter.java logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ThrowableAttributeConverter.java logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/package-info.java logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/TestBasicEntity.java logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextMapAttributeConverterTest.java logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextMapJsonAttributeConverterTest.java logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextStackAttributeConverterTest.java logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextStackJsonAttributeConverterTest.java logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/MarkerAttributeConverterTest.java logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/MessageAttributeConverterTest.java logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/StackTraceElementAttributeConverterTest.java logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ThrowableAttributeConverterTest.java logging/log4j/log4j2/trunk/core/src/test/resources/org/apache/logging/log4j/core/appender/db/jdbc/log4j2-data-source.xml logging/log4j/log4j2/trunk/core/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-jpa-base.xml - copied, changed from r1481329, logging/log4j/log4j2/trunk/core/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-jpa.xml logging/log4j/log4j2/trunk/core/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-jpa-basic.xml Removed: logging/log4j/log4j2/trunk/core/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-jpa.xml Modified: logging/log4j/log4j2/trunk/core/pom.xml logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/LogEventWrapperEntity.java logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/package-info.java logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JDBCAppenderTest.java logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/JPAAppenderTest.java logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/TestEntity.java logging/log4j/log4j2/trunk/core/src/test/resources/META-INF/persistence.xml logging/log4j/log4j2/trunk/core/src/test/resources/org/apache/logging/log4j/core/appender/db/jdbc/log4j2-driver-manager.xml logging/log4j/log4j2/trunk/core/src/test/resources/org/apache/logging/log4j/core/appender/db/jdbc/log4j2-factory-method.xml logging/log4j/log4j2/trunk/pom.xml Modified: logging/log4j/log4j2/trunk/core/pom.xml URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/pom.xml?rev=1481664&r1=1481663&r2=1481664&view=diff ============================================================================== --- logging/log4j/log4j2/trunk/core/pom.xml (original) +++ logging/log4j/log4j2/trunk/core/pom.xml Sun May 12 22:52:10 2013 @@ -136,7 +136,7 @@ org.hibernate.javax.persistence - hibernate-jpa-2.0-api + hibernate-jpa-2.1-api compile true Added: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/LogEventEntity.java URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/LogEventEntity.java?rev=1481664&view=auto ============================================================================== --- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/LogEventEntity.java (added) +++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/LogEventEntity.java Sun May 12 22:52:10 2013 @@ -0,0 +1,126 @@ +package org.apache.logging.log4j.core.appender.db.jpa; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.Marker; +import org.apache.logging.log4j.ThreadContext; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.appender.db.jpa.converter.ContextMapAttributeConverter; +import org.apache.logging.log4j.core.appender.db.jpa.converter.ContextStackAttributeConverter; +import org.apache.logging.log4j.core.appender.db.jpa.converter.MarkerAttributeConverter; +import org.apache.logging.log4j.core.appender.db.jpa.converter.MessageAttributeConverter; +import org.apache.logging.log4j.core.appender.db.jpa.converter.StackTraceElementAttributeConverter; +import org.apache.logging.log4j.core.appender.db.jpa.converter.ThrowableAttributeConverter; +import org.apache.logging.log4j.message.Message; + +import javax.persistence.Basic; +import javax.persistence.Convert; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.MappedSuperclass; +import java.util.Map; + +/** + * Users of the JPA appender may want to extend this class instead of {@link LogEventWrapperEntity}. This class + * implements all of the required mutator methods but does not implement a mutable entity ID property. In order to + * create an entity based on this class, you need only create two constructors matching this class's + * constructors, annotate the class {@link javax.persistence.Entity @Entity} and {@link javax.persistence.Table @Table}, + * and implement the fully mutable entity ID property annotated with {@link javax.persistence.Id @Id} and + * {@link javax.persistence.GeneratedValue @GeneratedValue} to tell the JPA provider how to calculate an ID for new + * events.
+ *
+ * The attributes in this entity use the default column names (which, according to the JPA spec, are the property names + * minus the "get" and "set" from the accessors/mutators). If you want to use different column names for one or more + * columns, override the necessary accessor methods defined in this class with the same annotations plus the + * {@link javax.persistence.Column @Column} annotation to specify the column name.
+ *
+ * The {@link #getContextMap()} and {@link #getContextStack()} attributes in this entity use the + * {@link ContextMapAttributeConverter} and {@link ContextStackAttributeConverter}, respectively. These convert the + * properties to simple strings that cannot be converted back to the properties. If you wish to instead convert these to + * a reversible JSON string, override these attributes with the same annotations but use the + * {@link org.apache.logging.log4j.core.appender.db.jpa.converter.ContextMapJsonAttributeConverter} and + * {@link org.apache.logging.log4j.core.appender.db.jpa.converter.ContextStackJsonAttributeConverter} instead.
+ *
+ * All other attributes in this entity use reversible converters that can be used for both persistence and retrieval. If + * there are any attributes you do not want persistent, you should override their accessor methods and annotate with + * {@link javax.persistence.Transient @Transient}. + * + * @see LogEventWrapperEntity + */ +@MappedSuperclass +public abstract class LogEventEntity extends LogEventWrapperEntity { + @SuppressWarnings("unused") // JPA requires this + public LogEventEntity() { + super(); + } + + public LogEventEntity(final LogEvent wrapped) { + super(wrapped); + } + + @Override + @Basic + @Enumerated(EnumType.STRING) + public Level getLevel() { + return this.getWrappedEvent().getLevel(); + } + + @Override + @Basic + public String getLoggerName() { + return this.getWrappedEvent().getLoggerName(); + } + + @Override + @Convert(converter = StackTraceElementAttributeConverter.class) + public StackTraceElement getSource() { + return this.getWrappedEvent().getSource(); + } + + @Override + @Convert(converter = MessageAttributeConverter.class) + public Message getMessage() { + return this.getWrappedEvent().getMessage(); + } + + @Override + @Convert(converter = MarkerAttributeConverter.class) + public Marker getMarker() { + return this.getWrappedEvent().getMarker(); + } + + @Override + @Basic + public String getThreadName() { + return this.getWrappedEvent().getThreadName(); + } + + @Override + @Basic + public long getMillis() { + return this.getWrappedEvent().getMillis(); + } + + @Override + @Convert(converter = ThrowableAttributeConverter.class) + public Throwable getThrown() { + return this.getWrappedEvent().getThrown(); + } + + @Override + @Convert(converter = ContextMapAttributeConverter.class) + public Map getContextMap() { + return this.getWrappedEvent().getContextMap(); + } + + @Override + @Convert(converter = ContextStackAttributeConverter.class) + public ThreadContext.ContextStack getContextStack() { + return this.getWrappedEvent().getContextStack(); + } + + @Override + @Basic + public String getFQCN() { + return this.getWrappedEvent().getFQCN(); + } +} Modified: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/LogEventWrapperEntity.java URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/LogEventWrapperEntity.java?rev=1481664&r1=1481663&r2=1481664&view=diff ============================================================================== --- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/LogEventWrapperEntity.java (original) +++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/LogEventWrapperEntity.java Sun May 12 22:52:10 2013 @@ -16,39 +16,43 @@ */ package org.apache.logging.log4j.core.appender.db.jpa; -import java.util.Map; - -import javax.persistence.MappedSuperclass; -import javax.persistence.Transient; - import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.message.Message; +import javax.persistence.MappedSuperclass; +import javax.persistence.Transient; +import java.util.Map; + /** - * Users of the JPA appender MUST implement this class, using JPA annotations on the concrete class and all of its + * Users of the JPA appender MUST extend this class, using JPA annotations on the concrete class and all of its * accessor methods (as needed) to map them to the proper table and columns. Accessors you do not want persisted should * be annotated with {@link Transient @Transient}. All accessors should call {@link #getWrappedEvent()} and delegate the - * call to the underlying event.
+ * call to the underlying event. Users may want to instead extend {@link LogEventEntity}, which takes care of all of + * this for you.
*
* The concrete class must have two constructors: a public no-arg constructor to convince the JPA provider that it's a - * valid entity (this constructor will call {@link #LogEventWrapperEntity(LogEvent) super(null)}), and a public - * constructor that takes a single {@link LogEvent event} and passes it to the parent class with - * {@link #LogEventWrapperEntity(LogEvent) super(event)}. The concrete class must also have a mutable - * {@link javax.persistence.Id @Id} property with fully-functional mutator and accessor methods (usually configured as a - * {@link javax.persistence.GeneratedValue @GeneratedValue} property, and should be annotated with - * {@link javax.persistence.Entity @Entity}
+ * valid entity, and a public constructor that takes a single {@link LogEvent event} and passes it to the parent class + * with {@link #LogEventWrapperEntity(LogEvent) super(event)}. Furthermore, the concrete class must be annotated + * {@link javax.persistence.Entity @Entity} and {@link javax.persistence.Table @Table} and must implement a fully + * mutable ID property annotated with {@link javax.persistence.Id @Id} and + * {@link javax.persistence.GeneratedValue @GeneratedValue} to tell the JPA provider how to calculate an ID for new + * events.
*
* Many of the return types of {@link LogEvent} methods (e.g., {@link StackTraceElement}, {@link Message}, - * {@link Marker}) will not be recognized by the JPA provider. In these cases, you must either implement custom - * persistence serializers or (probably easier) mark those methods {@link Transient @Transient} and create - * similar methods that return the String form of these properties.
+ * {@link Marker}, {@link Throwable}, {@link ThreadContext.ContextStack}, and {@link Map Map<String, String>}) will + * not be recognized by the JPA provider. In conjunction with {@link javax.persistence.Convert @Convert}, you can use + * the converters in the {@link org.apache.logging.log4j.core.appender.db.jpa.converter} package to convert these + * types to database columns. If you want to retrieve log events from the database, you can create a true POJO entity + * and also use these converters for extracting persisted values.
*
* The mutator methods in this class not specified in {@link LogEvent} are no-op methods, implemented to satisfy the JPA * requirement that accessor methods have matching mutator methods. If you create additional accessor methods, you must * likewise create matching no-op mutator methods. + * + * @see LogEventEntity */ @MappedSuperclass public abstract class LogEventWrapperEntity implements LogEvent { @@ -58,6 +62,11 @@ public abstract class LogEventWrapperEnt private static final long serialVersionUID = 1L; private final LogEvent wrappedEvent; + @SuppressWarnings("unused") // JPA requires this + protected LogEventWrapperEntity() { + this(null); + } + /** * Instantiates the base class. All concrete implementations must have two constructors: a no-arg constructor that * calls this constructor with a null argument, and a constructor matching this constructor's signature. @@ -79,82 +88,137 @@ public abstract class LogEventWrapperEnt return this.wrappedEvent; } - @Override - @Transient - public final boolean isEndOfBatch() { - return this.getWrappedEvent().isEndOfBatch(); - } - - @Override - @Transient - public final boolean isIncludeLocation() { - return this.getWrappedEvent().isIncludeLocation(); - } - + /** + * A no-op mutator to satisfy JPA requirements, as this entity is write-only. + * + * @param level Ignored. + */ @SuppressWarnings("unused") - public void setContextMap(final Map contextMap) { + public void setLevel(final Level level) { // this entity is write-only } + /** + * A no-op mutator to satisfy JPA requirements, as this entity is write-only. + * + * @param loggerName Ignored. + */ @SuppressWarnings("unused") - public void setContextStack(final ThreadContext.ContextStack contextStack) { + public void setLoggerName(final String loggerName) { // this entity is write-only } - @Override - @Transient - public final void setEndOfBatch(final boolean endOfBatch) { - this.getWrappedEvent().setEndOfBatch(endOfBatch); - } - + /** + * A no-op mutator to satisfy JPA requirements, as this entity is write-only. + * + * @param source Ignored. + */ @SuppressWarnings("unused") - public void setFQCN(final String fqcn) { + public void setSource(final StackTraceElement source) { // this entity is write-only } - @Override - @Transient - public final void setIncludeLocation(final boolean locationRequired) { - this.getWrappedEvent().setIncludeLocation(locationRequired); - } - + /** + * A no-op mutator to satisfy JPA requirements, as this entity is write-only. + * + * @param message Ignored. + */ @SuppressWarnings("unused") - public void setLevel(final Level level) { + public void setMessage(final Message message) { // this entity is write-only } + /** + * A no-op mutator to satisfy JPA requirements, as this entity is write-only. + * + * @param marker Ignored. + */ @SuppressWarnings("unused") - public void setLoggerName(final String name) { + public void setMarker(final Marker marker) { // this entity is write-only } + /** + * A no-op mutator to satisfy JPA requirements, as this entity is write-only. + * + * @param threadName Ignored. + */ @SuppressWarnings("unused") - public void setMarker(final Marker marker) { + public void setThreadName(final String threadName) { // this entity is write-only } + /** + * A no-op mutator to satisfy JPA requirements, as this entity is write-only. + * + * @param millis Ignored. + */ @SuppressWarnings("unused") - public void setMessage(final Message message) { + public void setMillis(final long millis) { // this entity is write-only } + /** + * A no-op mutator to satisfy JPA requirements, as this entity is write-only. + * + * @param throwable Ignored. + */ @SuppressWarnings("unused") - public void setMillis(final long millis) { + public void setThrown(final Throwable throwable) { // this entity is write-only } + /** + * A no-op mutator to satisfy JPA requirements, as this entity is write-only. + * + * @param contextMap Ignored. + */ @SuppressWarnings("unused") - public void setSource(final StackTraceElement element) { + public void setContextMap(final Map contextMap) { // this entity is write-only } + /** + * A no-op mutator to satisfy JPA requirements, as this entity is write-only. + * + * @param contextStack Ignored. + */ @SuppressWarnings("unused") - public void setThreadName(final String name) { + public void setContextStack(final ThreadContext.ContextStack contextStack) { // this entity is write-only } + /** + * A no-op mutator to satisfy JPA requirements, as this entity is write-only. + * + * @param fqcn Ignored. + */ @SuppressWarnings("unused") - public void setThrown(final Throwable throwable) { + public void setFQCN(final String fqcn) { // this entity is write-only } + + @Override + @Transient + public final boolean isIncludeLocation() { + return this.getWrappedEvent().isIncludeLocation(); + } + + @Override + @Transient + public final void setIncludeLocation(final boolean locationRequired) { + this.getWrappedEvent().setIncludeLocation(locationRequired); + } + + @Override + @Transient + public final boolean isEndOfBatch() { + return this.getWrappedEvent().isEndOfBatch(); + } + + @Override + @Transient + public final void setEndOfBatch(final boolean endOfBatch) { + this.getWrappedEvent().setEndOfBatch(endOfBatch); + } } Added: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextMapAttributeConverter.java URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextMapAttributeConverter.java?rev=1481664&view=auto ============================================================================== --- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextMapAttributeConverter.java (added) +++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextMapAttributeConverter.java Sun May 12 22:52:10 2013 @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.core.appender.db.jpa.converter; + +import javax.persistence.AttributeConverter; +import javax.persistence.Converter; +import java.util.Map; + +/** + * A JPA 2.1 attribute converter for {@link Map Map<String, String>}s in + * {@link org.apache.logging.log4j.core.LogEvent}s. This converter is only capable of converting to {@link String}s. The + * {@link #convertToEntityAttribute(String)} method throws an {@link UnsupportedOperationException}. If you need to + * support converting to an entity attribute, you should use the {@link ContextMapJsonAttributeConverter} for conversion + * both ways. + */ +@Converter(autoApply = false) +public class ContextMapAttributeConverter implements AttributeConverter, String> { + @Override + public String convertToDatabaseColumn(final Map contextMap) { + return contextMap.toString(); + } + + @Override + public Map convertToEntityAttribute(final String s) { + throw new UnsupportedOperationException("Log events can only be persisted, not extracted."); + } +} Added: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextMapJsonAttributeConverter.java URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextMapJsonAttributeConverter.java?rev=1481664&view=auto ============================================================================== --- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextMapJsonAttributeConverter.java (added) +++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextMapJsonAttributeConverter.java Sun May 12 22:52:10 2013 @@ -0,0 +1,41 @@ +package org.apache.logging.log4j.core.appender.db.jpa.converter; + +import org.codehaus.jackson.map.ObjectMapper; +import org.codehaus.jackson.type.TypeReference; + +import javax.persistence.AttributeConverter; +import javax.persistence.PersistenceException; +import java.io.IOException; +import java.util.Map; + +/** + * A JPA 2.1 attribute converter for {@link Map Map<String, String>}s in + * {@link org.apache.logging.log4j.core.LogEvent}s. This converter is capable of converting both to and from + * {@link String}s. + * + * In addition to other optional dependencies required by the JPA appender, this converter requires the Jackson Mapper. + */ +public class ContextMapJsonAttributeConverter implements AttributeConverter, String> { + static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); + + @Override + public String convertToDatabaseColumn(final Map contextMap) { + try { + return OBJECT_MAPPER.writeValueAsString(contextMap); + } catch (IOException e) { + throw new PersistenceException("Failed to convert map to JSON string.", e); + } + } + + @Override + public Map convertToEntityAttribute(final String s) { + if (s == null || s.length() == 0) { + return null; + } + try { + return OBJECT_MAPPER.readValue(s, new TypeReference>() { }); + } catch (IOException e) { + throw new PersistenceException("Failed to convert JSON string to map.", e); + } + } +} Added: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextStackAttributeConverter.java URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextStackAttributeConverter.java?rev=1481664&view=auto ============================================================================== --- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextStackAttributeConverter.java (added) +++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextStackAttributeConverter.java Sun May 12 22:52:10 2013 @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.core.appender.db.jpa.converter; + +import org.apache.logging.log4j.ThreadContext; + +import javax.persistence.AttributeConverter; +import javax.persistence.Converter; + +/** + * A JPA 2.1 attribute converter for {@link ThreadContext.ContextStack}s in + * {@link org.apache.logging.log4j.core.LogEvent}s. This converter is only capable of converting to {@link String}s. The + * {@link #convertToEntityAttribute(String)} method throws an {@link UnsupportedOperationException}. If you need to + * support converting to an entity attribute, you should use the {@link ContextStackJsonAttributeConverter} for + * conversion both ways. + */ +@Converter(autoApply = false) +public class ContextStackAttributeConverter implements AttributeConverter { + @Override + public String convertToDatabaseColumn(final ThreadContext.ContextStack contextStack) { + StringBuilder builder = new StringBuilder(); + for (String value : contextStack.asList()) { + if (builder.length() > 0) { + builder.append('\n'); + } + builder.append(value); + } + return builder.toString(); + } + + @Override + public ThreadContext.ContextStack convertToEntityAttribute(final String s) { + throw new UnsupportedOperationException("Log events can only be persisted, not extracted."); + } +} Added: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextStackJsonAttributeConverter.java URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextStackJsonAttributeConverter.java?rev=1481664&view=auto ============================================================================== --- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextStackJsonAttributeConverter.java (added) +++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextStackJsonAttributeConverter.java Sun May 12 22:52:10 2013 @@ -0,0 +1,43 @@ +package org.apache.logging.log4j.core.appender.db.jpa.converter; + +import org.apache.logging.log4j.ThreadContext; +import org.codehaus.jackson.type.TypeReference; + +import javax.persistence.AttributeConverter; +import javax.persistence.PersistenceException; +import java.io.IOException; +import java.util.List; + +/** + * A JPA 2.1 attribute converter for {@link ThreadContext.ContextStack}s in + * {@link org.apache.logging.log4j.core.LogEvent}s. This converter is capable of converting both to and from + * {@link String}s. + * + * In addition to other optional dependencies required by the JPA appender, this converter requires the Jackson Mapper. + */ +public class ContextStackJsonAttributeConverter implements AttributeConverter { + @Override + public String convertToDatabaseColumn(final ThreadContext.ContextStack contextStack) { + try { + return ContextMapJsonAttributeConverter.OBJECT_MAPPER.writeValueAsString(contextStack.asList()); + } catch (IOException e) { + throw new PersistenceException("Failed to convert stack list to JSON string.", e); + } + } + + @Override + public ThreadContext.ContextStack convertToEntityAttribute(final String s) { + if (s == null || s.length() == 0) { + return null; + } + + List list; + try { + list = ContextMapJsonAttributeConverter.OBJECT_MAPPER.readValue(s, new TypeReference>(){ }); + } catch (IOException e) { + throw new PersistenceException("Failed to convert JSON string to list for stack.", e); + } + + return new ThreadContext.ImmutableStack(list); + } +} Added: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/MarkerAttributeConverter.java URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/MarkerAttributeConverter.java?rev=1481664&view=auto ============================================================================== --- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/MarkerAttributeConverter.java (added) +++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/MarkerAttributeConverter.java Sun May 12 22:52:10 2013 @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.core.appender.db.jpa.converter; + +import org.apache.logging.log4j.Marker; +import org.apache.logging.log4j.MarkerManager; + +import javax.persistence.AttributeConverter; +import javax.persistence.Converter; + +/** + * A JPA 2.1 attribute converter for {@link Marker}s in {@link org.apache.logging.log4j.core.LogEvent}s. This + * converter is capable of converting both to and from {@link String}s. + */ +@Converter(autoApply = false) +public class MarkerAttributeConverter implements AttributeConverter { + @Override + public String convertToDatabaseColumn(final Marker marker) { + StringBuilder builder = new StringBuilder(marker.getName()); + Marker parent = marker.getParent(); + int levels = 0; + boolean hasParent = false; + while (parent != null) { + levels++; + hasParent = true; + builder.append("[ ").append(parent.getName()); + parent = parent.getParent(); + } + for (int i = 0; i < levels; i++) { + builder.append(" ]"); + } + if (hasParent) { + builder.append(" ]"); + } + return builder.toString(); + } + + @Override + public Marker convertToEntityAttribute(final String s) { + int bracket = s.indexOf("["); + + return bracket < 1 ? MarkerManager.getMarker(s) : MarkerManager.getMarker(s.substring(0, bracket)); + } +} Added: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/MessageAttributeConverter.java URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/MessageAttributeConverter.java?rev=1481664&view=auto ============================================================================== --- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/MessageAttributeConverter.java (added) +++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/MessageAttributeConverter.java Sun May 12 22:52:10 2013 @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.core.appender.db.jpa.converter; + +import org.apache.logging.log4j.message.Message; +import org.apache.logging.log4j.status.StatusLogger; + +import javax.persistence.AttributeConverter; +import javax.persistence.Converter; + +/** + * A JPA 2.1 attribute converter for {@link Message}s in {@link org.apache.logging.log4j.core.LogEvent}s. This + * converter is capable of converting both to and from {@link String}s. + */ +@Converter(autoApply = false) +public class MessageAttributeConverter implements AttributeConverter { + private static final StatusLogger log = StatusLogger.getLogger(); + + @Override + public String convertToDatabaseColumn(final Message message) { + return message.getFormattedMessage(); + } + + @Override + public Message convertToEntityAttribute(final String s) { + return log.getMessageFactory().newMessage(s); + } +} Added: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/StackTraceElementAttributeConverter.java URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/StackTraceElementAttributeConverter.java?rev=1481664&view=auto ============================================================================== --- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/StackTraceElementAttributeConverter.java (added) +++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/StackTraceElementAttributeConverter.java Sun May 12 22:52:10 2013 @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.core.appender.db.jpa.converter; + +import javax.persistence.AttributeConverter; + +/** + * A JPA 2.1 attribute converter for {@link StackTraceElement}s in {@link org.apache.logging.log4j.core.LogEvent}s. This + * converter is capable of converting both to and from {@link String}s. + */ +public class StackTraceElementAttributeConverter implements AttributeConverter { + @Override + public String convertToDatabaseColumn(final StackTraceElement element) { + return element.toString(); + } + + @Override + public StackTraceElement convertToEntityAttribute(final String s) { + return StackTraceElementAttributeConverter.convertString(s); + } + + static StackTraceElement convertString(final String s) { + int open = s.indexOf("("); + + String classMethod = s.substring(0, open); + String className = classMethod.substring(0, classMethod.lastIndexOf(".")); + String methodName = classMethod.substring(classMethod.lastIndexOf(".") + 1); + + String parenthesisContents = s.substring(open + 1, s.indexOf(")")); + + String fileName = null; + int lineNumber = -1; + if ("Native Method".equals(parenthesisContents)) { + lineNumber = -2; + } else if (!"Unknown Source".equals(parenthesisContents)) { + int colon = parenthesisContents.indexOf(":"); + if (colon > -1) { + fileName = parenthesisContents.substring(0, colon); + try { + lineNumber = Integer.parseInt(parenthesisContents.substring(colon + 1)); + } catch (NumberFormatException ignore) { + // we don't care + } + } else { + fileName = parenthesisContents.substring(0); + } + } + + return new StackTraceElement(className, methodName, fileName, lineNumber); + } +} Added: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ThrowableAttributeConverter.java URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ThrowableAttributeConverter.java?rev=1481664&view=auto ============================================================================== --- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ThrowableAttributeConverter.java (added) +++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ThrowableAttributeConverter.java Sun May 12 22:52:10 2013 @@ -0,0 +1,227 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.logging.log4j.core.appender.db.jpa.converter; + +import javax.persistence.AttributeConverter; +import javax.persistence.Converter; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.ListIterator; + +/** + * A JPA 2.1 attribute converter for {@link Throwable}s in {@link org.apache.logging.log4j.core.LogEvent}s. This + * converter is capable of converting both to and from {@link String}s. + */ +@Converter(autoApply = false) +public class ThrowableAttributeConverter implements AttributeConverter { + private static final Field THROWABLE_CAUSE; + + private static final Field THROWABLE_MESSAGE; + + static { + try { + THROWABLE_CAUSE = Throwable.class.getDeclaredField("cause"); + THROWABLE_CAUSE.setAccessible(true); + THROWABLE_MESSAGE = Throwable.class.getDeclaredField("detailMessage"); + THROWABLE_MESSAGE.setAccessible(true); + } catch (NoSuchFieldException e) { + throw new IllegalStateException("Something is wrong with java.lang.Throwable.", e); + } + } + + @Override + public String convertToDatabaseColumn(final Throwable throwable) { + StringBuilder builder = new StringBuilder(); + this.convertThrowable(builder, throwable); + return builder.toString(); + } + + private void convertThrowable(final StringBuilder builder, final Throwable throwable) { + builder.append(throwable.toString()).append('\n'); + for (StackTraceElement element : throwable.getStackTrace()) { + builder.append("\tat ").append(element).append('\n'); + } + if (throwable.getCause() != null) { + builder.append("Caused by "); + this.convertThrowable(builder, throwable.getCause()); + } + } + + @Override + public Throwable convertToEntityAttribute(final String s) { + if (s == null || s.length() == 0) { + return null; + } + + List lines = Arrays.asList(s.split("(\n|\r\n)")); + return this.convertString(lines.listIterator(), false); + } + + private Throwable convertString(final ListIterator lines, boolean removeCausedBy) { + String firstLine = lines.next(); + if (removeCausedBy) { + firstLine = firstLine.substring(10); + } + int colon = firstLine.indexOf(":"); + String throwableClassName; + String message = null; + if (colon > 1) { + throwableClassName = firstLine.substring(0, colon); + if (firstLine.length() > colon + 1) { + message = firstLine.substring(colon + 1).trim(); + } + } else { + throwableClassName = firstLine; + } + + List stackTrace = new ArrayList(); + Throwable cause = null; + while (lines.hasNext()) { + String line = lines.next(); + + if (line.startsWith("Caused by ")) { + lines.previous(); + cause = convertString(lines, true); + break; + } + + stackTrace.add( + StackTraceElementAttributeConverter.convertString(line.trim().substring(3).trim()) + ); + } + + return this.getThrowable(throwableClassName, message, cause, + stackTrace.toArray(new StackTraceElement[stackTrace.size()])); + } + + private Throwable getThrowable(final String throwableClassName, final String message, final Throwable cause, + final StackTraceElement[] stackTrace) { + try { + @SuppressWarnings("unchecked") + Class throwableClass = (Class)Class.forName(throwableClassName); + + if (!Throwable.class.isAssignableFrom(throwableClass)) { + return null; + } + + Throwable throwable; + if (message != null && cause != null) { + throwable = this.getThrowable(throwableClass, message, cause); + if (throwable == null) { + throwable = this.getThrowable(throwableClass, cause); + if (throwable == null) { + throwable = this.getThrowable(throwableClass, message); + if (throwable == null) { + throwable = this.getThrowable(throwableClass); + if (throwable != null) { + THROWABLE_MESSAGE.set(throwable, message); + THROWABLE_CAUSE.set(throwable, cause); + } + } else { + THROWABLE_CAUSE.set(throwable, cause); + } + } else { + THROWABLE_MESSAGE.set(throwable, message); + } + } + } else if (cause != null) { + throwable = this.getThrowable(throwableClass, cause); + if (throwable == null) { + throwable = this.getThrowable(throwableClass); + if (throwable != null) { + THROWABLE_CAUSE.set(throwable, cause); + } + } + } else if (message != null) { + throwable = this.getThrowable(throwableClass, message); + if (throwable == null) { + throwable = this.getThrowable(throwableClass); + if (throwable != null) { + THROWABLE_MESSAGE.set(throwable, cause); + } + } + } else { + throwable = this.getThrowable(throwableClass); + } + + if (throwable == null) { + return null; + } else { + throwable.setStackTrace(stackTrace); + return throwable; + } + } catch (Exception e) { + return null; + } + } + + private Throwable getThrowable(final Class throwableClass, final String message, final Throwable cause) { + try { + @SuppressWarnings("unchecked") + Constructor[] constructors = (Constructor[])throwableClass.getConstructors(); + for (Constructor constructor : constructors) { + Class[] parameterTypes = constructor.getParameterTypes(); + if (parameterTypes.length == 2) { + if (String.class == parameterTypes[0] && Throwable.class.isAssignableFrom(parameterTypes[1])) { + return constructor.newInstance(message, cause); + } else if (String.class == parameterTypes[1] && + Throwable.class.isAssignableFrom(parameterTypes[0])) { + return constructor.newInstance(cause, message); + } + } + } + return null; + } catch (Exception e) { + return null; + } + } + + private Throwable getThrowable(final Class throwableClass, final Throwable cause) { + try { + @SuppressWarnings("unchecked") + Constructor[] constructors = (Constructor[])throwableClass.getConstructors(); + for (Constructor constructor : constructors) { + Class[] parameterTypes = constructor.getParameterTypes(); + if (parameterTypes.length == 1 && Throwable.class.isAssignableFrom(parameterTypes[0])) { + return constructor.newInstance(cause); + } + } + return null; + } catch (Exception e) { + return null; + } + } + + private Throwable getThrowable(final Class throwableClass, final String message) { + try { + return throwableClass.getConstructor(String.class).newInstance(message); + } catch (Exception e) { + return null; + } + } + + private Throwable getThrowable(final Class throwableClass) { + try { + return throwableClass.newInstance(); + } catch (Exception e) { + return null; + } + } +} Added: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/package-info.java URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/package-info.java?rev=1481664&view=auto ============================================================================== --- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/package-info.java (added) +++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/package-info.java Sun May 12 22:52:10 2013 @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +/** + * The converters in this package implement the JPA 2.1 mechanism for converting non-standard types to and from + * database fields. Most of these types are capable of two-way conversion and can be used to both persist and retrieve + * entities. The {@link ContextMapAttributeConverter} and {@link ContextStackAttributeConverter} only support + * persistence and not retrieval, persisting the type as a simple string. You can use the + * {@link ContextMapJsonAttributeConverter} and {@link ContextStackJsonAttributeConverter} instead, which require the + * Jackson Mapper dependency to also be on your class path. + */ +package org.apache.logging.log4j.core.appender.db.jpa.converter; Modified: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/package-info.java URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/package-info.java?rev=1481664&r1=1481663&r2=1481664&view=diff ============================================================================== --- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/package-info.java (original) +++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/package-info.java Sun May 12 22:52:10 2013 @@ -16,9 +16,8 @@ */ /** * The JPA Appender supports writing log events to a relational database using the Java Persistence API. You will need - * a JDBC driver on your classpath for the database you wish to log to. You will also need the Java Persistence API + * a JDBC driver on your classpath for the database you wish to log to. You will also need the Java Persistence API 2.1 * and your JPA provider of choice on the class path; these Maven dependencies are optional and will not automatically * be added to your classpath. */ package org.apache.logging.log4j.core.appender.db.jpa; - Modified: logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JDBCAppenderTest.java URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JDBCAppenderTest.java?rev=1481664&r1=1481663&r2=1481664&view=diff ============================================================================== --- logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JDBCAppenderTest.java (original) +++ logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JDBCAppenderTest.java Sun May 12 22:52:10 2013 @@ -16,11 +16,20 @@ */ package org.apache.logging.log4j.core.appender.db.jdbc; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.Appender; +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.config.ConfigurationFactory; +import org.apache.logging.log4j.core.config.DefaultConfiguration; +import org.apache.logging.log4j.status.StatusLogger; +import org.easymock.IAnswer; +import org.junit.After; +import org.junit.Test; +import org.mockejb.jndi.MockContextFactory; +import javax.naming.InitialContext; +import javax.sql.DataSource; import java.io.ByteArrayOutputStream; import java.io.PrintWriter; import java.sql.Connection; @@ -30,31 +39,20 @@ import java.sql.SQLException; import java.sql.Statement; import java.util.Map; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.core.Appender; -import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.config.ConfigurationFactory; -import org.apache.logging.log4j.core.config.DefaultConfiguration; -import org.apache.logging.log4j.status.StatusLogger; -import org.junit.After; -import org.junit.Test; +import static org.easymock.EasyMock.*; +import static org.junit.Assert.*; public class JDBCAppenderTest { - @SuppressWarnings("unused") - public static Connection testFactoryMethodConfigMethod() throws SQLException { - return DriverManager.getConnection("jdbc:hsqldb:mem:Log4j;ifexists=true", "sa", ""); - } - private Connection connection; public void setUp(final String tableName, final String configFileName) throws SQLException { this.connection = DriverManager.getConnection("jdbc:hsqldb:mem:Log4j", "sa", ""); final Statement statement = this.connection.createStatement(); - statement.executeUpdate("CREATE TABLE " + tableName + " ( " - + "id INTEGER IDENTITY, eventDate DATETIME, literalColumn VARCHAR(255), level VARCHAR(10), " - + "logger VARCHAR(255), message VARCHAR(1024), exception VARCHAR(1048576)" + " )"); + statement.executeUpdate("CREATE TABLE " + tableName + " ( " + + "id INTEGER IDENTITY, eventDate DATETIME, literalColumn VARCHAR(255), level VARCHAR(10), " + + "logger VARCHAR(255), message VARCHAR(1024), exception VARCHAR(1048576)" + + " )"); statement.close(); System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY, @@ -192,4 +190,77 @@ public class JDBCAppenderTest { assertFalse("There should not be three rows.", resultSet.next()); } + + @Test + public void testDataSourceConfig() throws Exception { + System.out.println("Before creating mock data source."); + DataSource dataSource = createStrictMock(DataSource.class); + + expect(dataSource.getConnection()).andAnswer(new IAnswer() { + @Override + public Connection answer() throws Throwable { + return DriverManager.getConnection("jdbc:hsqldb:mem:Log4j", "sa", ""); + } + }).atLeastOnce(); + replay(dataSource); + + System.out.println("Before creating mock context."); + MockContextFactory.setAsInitial(); + + System.out.println("Before instantiating context."); + InitialContext context = new InitialContext(); + context.createSubcontext("java:"); + context.createSubcontext("java:/comp"); + context.createSubcontext("java:/comp/env"); + context.createSubcontext("java:/comp/env/jdbc"); + + System.out.println("Before binding data source."); + context.bind("java:/comp/env/jdbc/TestDataSourceAppender", dataSource); + + try { + System.out.println("Before setting up."); + this.setUp("dsLogEntry", "log4j2-data-source.xml"); + + System.out.println("After setting up."); + final Error exception = new Error("Final error massage is fatal!"); + final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + final PrintWriter writer = new PrintWriter(outputStream); + exception.printStackTrace(writer); + writer.close(); + final String stackTrace = outputStream.toString(); + + final long millis = System.currentTimeMillis(); + + final Logger logger = LogManager.getLogger(this.getClass().getName() + ".testDataSourceConfig"); + logger.trace("Data source logged message 01."); + logger.fatal("Error from data source 02.", exception); + + final Statement statement = this.connection.createStatement(); + final ResultSet resultSet = statement.executeQuery("SELECT * FROM dsLogEntry ORDER BY id"); + + assertTrue("There should be at least one row.", resultSet.next()); + + long date = resultSet.getTimestamp("eventDate").getTime(); + assertTrue("The date should be later than pre-logging (1).", date >= millis); + assertTrue("The date should be earlier than now (1).", date <= System.currentTimeMillis()); + assertEquals("The literal column is not correct (1).", "Literal Value of Data Source", + resultSet.getString("literalColumn")); + assertEquals("The level column is not correct (1).", "FATAL", resultSet.getString("level")); + assertEquals("The logger column is not correct (1).", logger.getName(), resultSet.getString("logger")); + assertEquals("The message column is not correct (1).", "Error from data source 02.", + resultSet.getString("message")); + assertEquals("The exception column is not correct (1).", stackTrace, resultSet.getString("exception")); + + assertFalse("There should not be two rows.", resultSet.next()); + + verify(dataSource); + } finally { + MockContextFactory.revertSetAsInitial(); + } + } + + @SuppressWarnings("unused") + public static Connection testFactoryMethodConfigMethod() throws SQLException { + return DriverManager.getConnection("jdbc:hsqldb:mem:Log4j;ifexists=true", "sa", ""); + } } Modified: logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/JPAAppenderTest.java URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/JPAAppenderTest.java?rev=1481664&r1=1481663&r2=1481664&view=diff ============================================================================== --- logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/JPAAppenderTest.java (original) +++ logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/JPAAppenderTest.java Sun May 12 22:52:10 2013 @@ -16,21 +16,6 @@ */ package org.apache.logging.log4j.core.appender.db.jpa; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import java.io.ByteArrayOutputStream; -import java.io.PrintWriter; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.Map; - import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.Appender; @@ -39,40 +24,38 @@ import org.apache.logging.log4j.core.Log import org.apache.logging.log4j.core.config.ConfigurationFactory; import org.apache.logging.log4j.core.config.DefaultConfiguration; import org.apache.logging.log4j.status.StatusLogger; +import org.junit.Ignore; import org.junit.Test; -public class JPAAppenderTest { - @SuppressWarnings("unused") - public static class BadConstructorEntity1 extends TestEntity { - private static final long serialVersionUID = 1L; - - public BadConstructorEntity1(final LogEvent wrappedEvent) { - super(wrappedEvent); - } - } - - @SuppressWarnings("unused") - public static class BadConstructorEntity2 extends TestEntity { - private static final long serialVersionUID = 1L; - - public BadConstructorEntity2() { - super(null); - } +import java.io.ByteArrayOutputStream; +import java.io.PrintWriter; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Map; - public BadConstructorEntity2(final LogEvent wrappedEvent, final String badParameter) { - super(wrappedEvent); - } - } +import static org.junit.Assert.*; +public class JPAAppenderTest { private Connection connection; public void setUp(final String configFileName) throws SQLException { this.connection = DriverManager.getConnection("jdbc:hsqldb:mem:Log4j", "sa", ""); - final Statement statement = this.connection.createStatement(); - statement.executeUpdate("CREATE TABLE jpaLogEntry ( " - + "id INTEGER IDENTITY, eventDate DATETIME, level VARCHAR(10), logger VARCHAR(255), " - + "message VARCHAR(1024), exception VARCHAR(1048576)" + " )"); + Statement statement = this.connection.createStatement(); + statement.executeUpdate("CREATE TABLE jpaBaseLogEntry ( " + + "id INTEGER IDENTITY, eventDate DATETIME, level VARCHAR(10), logger VARCHAR(255), " + + "message VARCHAR(1024), exception VARCHAR(1048576)" + + " )"); + statement.close(); + + statement = this.connection.createStatement(); + statement.executeUpdate("CREATE TABLE jpaBasicLogEntry ( " + + "id INTEGER IDENTITY, millis BIGINT, level VARCHAR(10), logger VARCHAR(255), " + + "message VARCHAR(1024), thrown VARCHAR(1048576), contextMapJson VARCHAR(1048576)" + + " )"); statement.close(); System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY, @@ -115,6 +98,29 @@ public class JPAAppenderTest { } @Test + public void testNoEntityClassName() { + final JPAAppender appender = JPAAppender.createAppender("name", null, null, null, null, "jpaAppenderTestUnit"); + + assertNull("The appender should be null.", appender); + } + + @Test + public void testNonLogEventEntity() { + final JPAAppender appender = JPAAppender.createAppender("name", null, null, null, Object.class.getName(), + "jpaAppenderTestUnit"); + + assertNull("The appender should be null.", appender); + } + + @Test + public void testNoPersistenceUnitName() { + final JPAAppender appender = JPAAppender.createAppender("name", null, null, null, TestEntity.class.getName(), + null); + + assertNull("The appender should be null.", appender); + } + + @Test public void testBadConstructorEntity01() { final JPAAppender appender = JPAAppender.createAppender("name", null, null, null, BadConstructorEntity1.class.getName(), "jpaAppenderTestUnit"); @@ -139,9 +145,10 @@ public class JPAAppenderTest { } @Test - public void testConfiguredAppender() throws SQLException { + @Ignore("until Hibernate implements support for @Convert, @Converter") + public void testBaseJpaEntityAppender() throws SQLException { try { - this.setUp("log4j2-jpa.xml"); + this.setUp("log4j2-jpa-base.xml"); final RuntimeException exception = new RuntimeException("Hello, world!"); final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); @@ -152,14 +159,14 @@ public class JPAAppenderTest { final long millis = System.currentTimeMillis(); - final Logger logger1 = LogManager.getLogger(this.getClass().getName() + ".testConfiguredAppender"); - final Logger logger2 = LogManager.getLogger(this.getClass().getName() + ".testConfiguredAppenderAgain"); + final Logger logger1 = LogManager.getLogger(this.getClass().getName() + ".testBaseJpaEntityAppender"); + final Logger logger2 = LogManager.getLogger(this.getClass().getName() + ".testBaseJpaEntityAppenderAgain"); logger1.info("Test my message 01."); logger1.error("This is another message 02.", exception); logger2.warn("A final warning has been issued."); final Statement statement = this.connection.createStatement(); - final ResultSet resultSet = statement.executeQuery("SELECT * FROM jpaLogEntry ORDER BY id"); + final ResultSet resultSet = statement.executeQuery("SELECT * FROM jpaBaseLogEntry ORDER BY id"); assertTrue("There should be at least one row.", resultSet.next()); @@ -201,25 +208,87 @@ public class JPAAppenderTest { } @Test - public void testNoEntityClassName() { - final JPAAppender appender = JPAAppender.createAppender("name", null, null, null, null, "jpaAppenderTestUnit"); + @Ignore("until Hibernate implements support for @Convert, @Converter") + public void testBasicJpaEntityAppender() throws SQLException { + try { + this.setUp("log4j2-jpa-basic.xml"); - assertNull("The appender should be null.", appender); + final Error exception = new Error("Goodbye, cruel world!"); + final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + final PrintWriter writer = new PrintWriter(outputStream); + exception.printStackTrace(writer); + writer.close(); + final String stackTrace = outputStream.toString(); + + final long millis = System.currentTimeMillis(); + + final Logger logger1 = LogManager.getLogger(this.getClass().getName() + ".testBasicJpaEntityAppender"); + final Logger logger2 = LogManager.getLogger(this.getClass().getName() + ".testBasicJpaEntityAppenderAgain"); + logger1.debug("Test my debug 01."); + logger1.warn("This is another warning 02.", exception); + logger2.fatal("A fatal warning has been issued."); + + final Statement statement = this.connection.createStatement(); + final ResultSet resultSet = statement.executeQuery("SELECT * FROM jpaBasicLogEntry ORDER BY id"); + + assertTrue("There should be at least one row.", resultSet.next()); + + long date = resultSet.getLong("millis"); + assertTrue("The date should be later than pre-logging (1).", date >= millis); + assertTrue("The date should be earlier than now (1).", date <= System.currentTimeMillis()); + assertEquals("The level column is not correct (1).", "DEBUG", resultSet.getString("level")); + assertEquals("The logger column is not correct (1).", logger1.getName(), resultSet.getString("logger")); + assertEquals("The message column is not correct (1).", "Test my debug 01.", + resultSet.getString("message")); + assertNull("The exception column is not correct (1).", resultSet.getString("exception")); + + assertTrue("There should be at least two rows.", resultSet.next()); + + date = resultSet.getLong("millis"); + assertTrue("The date should be later than pre-logging (2).", date >= millis); + assertTrue("The date should be earlier than now (2).", date <= System.currentTimeMillis()); + assertEquals("The level column is not correct (2).", "WARN", resultSet.getString("level")); + assertEquals("The logger column is not correct (2).", logger1.getName(), resultSet.getString("logger")); + assertEquals("The message column is not correct (2).", "This is another warning 02.", + resultSet.getString("message")); + assertEquals("The exception column is not correct (2).", stackTrace, resultSet.getString("exception")); + + assertTrue("There should be three rows.", resultSet.next()); + + date = resultSet.getLong("millis"); + assertTrue("The date should be later than pre-logging (3).", date >= millis); + assertTrue("The date should be earlier than now (3).", date <= System.currentTimeMillis()); + assertEquals("The level column is not correct (3).", "FATAL", resultSet.getString("level")); + assertEquals("The logger column is not correct (3).", logger2.getName(), resultSet.getString("logger")); + assertEquals("The message column is not correct (3).", "A fatal warning has been issued.", + resultSet.getString("message")); + assertNull("The exception column is not correct (3).", resultSet.getString("exception")); + + assertFalse("There should not be four rows.", resultSet.next()); + } finally { + this.tearDown(); + } } - @Test - public void testNonLogEventEntity() { - final JPAAppender appender = JPAAppender.createAppender("name", null, null, null, Object.class.getName(), - "jpaAppenderTestUnit"); + @SuppressWarnings("unused") + public static class BadConstructorEntity1 extends TestEntity { + private static final long serialVersionUID = 1L; - assertNull("The appender should be null.", appender); + public BadConstructorEntity1(final LogEvent wrappedEvent) { + super(wrappedEvent); + } } - @Test - public void testNoPersistenceUnitName() { - final JPAAppender appender = JPAAppender.createAppender("name", null, null, null, TestEntity.class.getName(), - null); + @SuppressWarnings("unused") + public static class BadConstructorEntity2 extends TestEntity { + private static final long serialVersionUID = 1L; - assertNull("The appender should be null.", appender); + public BadConstructorEntity2() { + super(null); + } + + public BadConstructorEntity2(final LogEvent wrappedEvent, final String badParameter) { + super(wrappedEvent); + } } } Added: logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/TestBasicEntity.java URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/TestBasicEntity.java?rev=1481664&view=auto ============================================================================== --- logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/TestBasicEntity.java (added) +++ logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/TestBasicEntity.java Sun May 12 22:52:10 2013 @@ -0,0 +1,81 @@ +package org.apache.logging.log4j.core.appender.db.jpa; + +import org.apache.logging.log4j.Marker; +import org.apache.logging.log4j.ThreadContext; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.appender.db.jpa.converter.ContextMapJsonAttributeConverter; + +import javax.persistence.Column; +import javax.persistence.Convert; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.persistence.Transient; +import java.util.Map; + +@Entity +@Table(name = "jpaBasicLogEntry") +@SuppressWarnings("unused") +public class TestBasicEntity extends LogEventEntity { + private static final long serialVersionUID = 1L; + + private long id = 0L; + + public TestBasicEntity() { + super(); + } + + public TestBasicEntity(final LogEvent wrapped) { + super(wrapped); + } + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + public long getId() { + return this.id; + } + + public void setId(final long id) { + this.id = id; + } + + @Override + @Convert(converter = ContextMapJsonAttributeConverter.class) + @Column(name = "contextMapJson") + public Map getContextMap() { + return super.getContextMap(); + } + + @Override + @Transient + public StackTraceElement getSource() { + return super.getSource(); + } + + @Override + @Transient + public Marker getMarker() { + return super.getMarker(); + } + + @Override + @Transient + public String getThreadName() { + return super.getThreadName(); + } + + @Override + @Transient + public ThreadContext.ContextStack getContextStack() { + return super.getContextStack(); + } + + @Override + @Transient + public String getFQCN() { + return super.getFQCN(); + } +} Modified: logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/TestEntity.java URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/TestEntity.java?rev=1481664&r1=1481663&r2=1481664&view=diff ============================================================================== --- logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/TestEntity.java (original) +++ logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/TestEntity.java Sun May 12 22:52:10 2013 @@ -16,13 +16,17 @@ */ package org.apache.logging.log4j.core.appender.db.jpa; -import java.io.ByteArrayOutputStream; -import java.io.PrintWriter; -import java.util.Date; -import java.util.Map; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.Marker; +import org.apache.logging.log4j.ThreadContext; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.appender.db.jpa.converter.MessageAttributeConverter; +import org.apache.logging.log4j.core.appender.db.jpa.converter.ThrowableAttributeConverter; +import org.apache.logging.log4j.message.Message; import javax.persistence.Basic; import javax.persistence.Column; +import javax.persistence.Convert; import javax.persistence.Entity; import javax.persistence.EnumType; import javax.persistence.Enumerated; @@ -33,15 +37,11 @@ import javax.persistence.Table; import javax.persistence.Temporal; import javax.persistence.TemporalType; import javax.persistence.Transient; - -import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.Marker; -import org.apache.logging.log4j.ThreadContext; -import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.message.Message; +import java.util.Date; +import java.util.Map; @Entity -@Table(name = "jpaLogEntry") +@Table(name = "jpaBaseLogEntry") @SuppressWarnings("unused") public class TestEntity extends LogEventWrapperEntity { private static final long serialVersionUID = 1L; @@ -49,23 +49,22 @@ public class TestEntity extends LogEvent private long id = 0L; public TestEntity() { - super(null); + super(); } public TestEntity(final LogEvent wrappedEvent) { super(wrappedEvent); } - @Override - @Transient - public Map getContextMap() { - return getWrappedEvent().getContextMap(); + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + public long getId() { + return this.id; } - @Override - @Transient - public ThreadContext.ContextStack getContextStack() { - return getWrappedEvent().getContextStack(); + public void setId(final long id) { + this.id = id; } @Temporal(TemporalType.TIMESTAMP) @@ -74,31 +73,8 @@ public class TestEntity extends LogEvent return new Date(this.getMillis()); } - @Basic - @Column(name = "exception") - @SuppressWarnings("ThrowableResultOfMethodCallIgnored") - public String getException() { - if (this.getThrown() != null) { - final ByteArrayOutputStream stream = new ByteArrayOutputStream(); - final PrintWriter writer = new PrintWriter(stream); - this.getThrown().printStackTrace(writer); - writer.close(); - return stream.toString(); - } - return null; - } - - @Override - @Transient - public String getFQCN() { - return getWrappedEvent().getFQCN(); - } - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "id") - public long getId() { - return this.id; + public void setEventDate(final Date date) { + // this entity is write-only } @Override @@ -117,59 +93,56 @@ public class TestEntity extends LogEvent @Override @Transient - public Marker getMarker() { - return getWrappedEvent().getMarker(); + public StackTraceElement getSource() { + return getWrappedEvent().getSource(); } @Override - @Transient + @Convert(converter = MessageAttributeConverter.class) public Message getMessage() { return getWrappedEvent().getMessage(); } - @Basic - @Column(name = "message") - public String getMessageString() { - return this.getMessage().getFormattedMessage(); - } - @Override @Transient - public long getMillis() { - return getWrappedEvent().getMillis(); + public Marker getMarker() { + return getWrappedEvent().getMarker(); } @Override @Transient - public StackTraceElement getSource() { - return getWrappedEvent().getSource(); + public String getThreadName() { + return getWrappedEvent().getThreadName(); } @Override @Transient - public String getThreadName() { - return getWrappedEvent().getThreadName(); + public long getMillis() { + return getWrappedEvent().getMillis(); } @Override - @Transient + @Convert(converter = ThrowableAttributeConverter.class) + @Column(name = "exception") public Throwable getThrown() { return getWrappedEvent().getThrown(); } - public void setEventDate(final Date date) { - // this entity is write-only - } - - public void setException(final String exception) { - // this entity is write-only + @Override + @Transient + public Map getContextMap() { + return getWrappedEvent().getContextMap(); } - public void setId(final long id) { - this.id = id; + @Override + @Transient + public ThreadContext.ContextStack getContextStack() { + return getWrappedEvent().getContextStack(); } - public void setMessageString(final String messageString) { - // this entity is write-only + @Override + @Transient + public String getFQCN() { + return getWrappedEvent().getFQCN(); } } Added: logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextMapAttributeConverterTest.java URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextMapAttributeConverterTest.java?rev=1481664&view=auto ============================================================================== --- logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextMapAttributeConverterTest.java (added) +++ logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextMapAttributeConverterTest.java Sun May 12 22:52:10 2013 @@ -0,0 +1,50 @@ +package org.apache.logging.log4j.core.appender.db.jpa.converter; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.*; + +public class ContextMapAttributeConverterTest { + private ContextMapAttributeConverter converter; + + @Before + public void setUp() { + this.converter = new ContextMapAttributeConverter(); + } + + @After + public void tearDown() { + + } + + @Test + public void testConvertToDatabaseColumn01() { + Map map = new HashMap(); + map.put("test1", "another1"); + map.put("key2", "value2"); + + assertEquals("The converted value is not correct.", map.toString(), + this.converter.convertToDatabaseColumn(map)); + } + + @Test + public void testConvertToDatabaseColumn02() { + Map map = new HashMap(); + map.put("someKey", "coolValue"); + map.put("anotherKey", "testValue"); + map.put("myKey", "yourValue"); + + assertEquals("The converted value is not correct.", map.toString(), + this.converter.convertToDatabaseColumn(map)); + } + + @Test(expected = UnsupportedOperationException.class) + public void testConvertToEntityAttribute() { + this.converter.convertToEntityAttribute(null); + } +} Added: logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextMapJsonAttributeConverterTest.java URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextMapJsonAttributeConverterTest.java?rev=1481664&view=auto ============================================================================== --- logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextMapJsonAttributeConverterTest.java (added) +++ logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextMapJsonAttributeConverterTest.java Sun May 12 22:52:10 2013 @@ -0,0 +1,57 @@ +package org.apache.logging.log4j.core.appender.db.jpa.converter; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.*; + +public class ContextMapJsonAttributeConverterTest { + private ContextMapJsonAttributeConverter converter; + + @Before + public void setUp() { + this.converter = new ContextMapJsonAttributeConverter(); + } + + @After + public void tearDown() { + + } + + @Test + public void testConvert01() { + Map map = new HashMap(); + map.put("test1", "another1"); + map.put("key2", "value2"); + + String converted = this.converter.convertToDatabaseColumn(map); + + assertNotNull("The converted value should not be null.", converted); + + Map reversed = this.converter.convertToEntityAttribute(converted); + + assertNotNull("The reversed value should not be null.", reversed); + assertEquals("The reversed value is not correct.", map, reversed); + } + + @Test + public void testConvert02() { + Map map = new HashMap(); + map.put("someKey", "coolValue"); + map.put("anotherKey", "testValue"); + map.put("myKey", "yourValue"); + + String converted = this.converter.convertToDatabaseColumn(map); + + assertNotNull("The converted value should not be null.", converted); + + Map reversed = this.converter.convertToEntityAttribute(converted); + + assertNotNull("The reversed value should not be null.", reversed); + assertEquals("The reversed value is not correct.", map, reversed); + } +} Added: logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextStackAttributeConverterTest.java URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextStackAttributeConverterTest.java?rev=1481664&view=auto ============================================================================== --- logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextStackAttributeConverterTest.java (added) +++ logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextStackAttributeConverterTest.java Sun May 12 22:52:10 2013 @@ -0,0 +1,45 @@ +package org.apache.logging.log4j.core.appender.db.jpa.converter; + +import org.apache.logging.log4j.ThreadContext; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.util.Arrays; + +import static org.junit.Assert.*; + +public class ContextStackAttributeConverterTest { + private ContextStackAttributeConverter converter; + + @Before + public void setUp() { + this.converter = new ContextStackAttributeConverter(); + } + + @After + public void tearDown() { + + } + + @Test + public void testConvertToDatabaseColumn01() { + ThreadContext.ContextStack stack = new ThreadContext.ImmutableStack(Arrays.asList("value1", "another2")); + + assertEquals("The converted value is not correct.", "value1\nanother2", + this.converter.convertToDatabaseColumn(stack)); + } + + @Test + public void testConvertToDatabaseColumn02() { + ThreadContext.ContextStack stack = new ThreadContext.ImmutableStack(Arrays.asList("key1", "value2", "my3")); + + assertEquals("The converted value is not correct.", "key1\nvalue2\nmy3", + this.converter.convertToDatabaseColumn(stack)); + } + + @Test(expected = UnsupportedOperationException.class) + public void testConvertToEntityAttribute() { + this.converter.convertToEntityAttribute(null); + } +}