You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by gg...@apache.org on 2014/05/21 21:37:10 UTC

svn commit: r1596658 [1/2] - in /logging/log4j/log4j2/trunk/log4j-core/src: main/java/org/apache/logging/log4j/core/appender/db/jdbc/ main/java/org/apache/logging/log4j/core/appender/db/jpa/ main/java/org/apache/logging/log4j/core/jackson/ main/java/or...

Author: ggregory
Date: Wed May 21 19:37:09 2014
New Revision: 1596658

URL: http://svn.apache.org/r1596658
Log:
Camel case changes as agreed upon on the ML (see the Java style guidelines in our manual). In particular, Camel Case is used even for acronyms. Note that not all type names have been changed yet as some are giving me headaches presumably due to running on Windows with SVN (Eclipse + Subclipse).

Added:
    logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppender.java   (with props)
    logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcDatabaseManager.java   (with props)
    logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/JpaAppender.java   (with props)
    logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/JpaDatabaseManager.java   (with props)
    logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/JsonConstants.java   (with props)
    logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/XmlConstants.java   (with props)
    logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/JsonLayout.java   (with props)
    logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/net/server/UdpSocketServer.java   (with props)
    logging/log4j/log4j2/trunk/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/JsonCompleteFileAppenderTest.java   (with props)
    logging/log4j/log4j2/trunk/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/JsonLayoutTest.java   (with props)
Removed:
    logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/JDBCAppender.java
    logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/JDBCDatabaseManager.java
    logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/JPAAppender.java
    logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/JPADatabaseManager.java
    logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/JSONConstants.java
    logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/XMLConstants.java
    logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/JSONLayout.java
    logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/net/server/UDPSocketServer.java
    logging/log4j/log4j2/trunk/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/JSONCompleteFileAppenderTest.java
    logging/log4j/log4j2/trunk/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/JSONLayoutTest.java
Modified:
    logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/ConnectionSource.java
    logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/DataSourceConnectionSource.java
    logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/FactoryMethodConnectionSource.java
    logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/LogEventMixIn.java
    logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/MarkerMixIn.java
    logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ThrowableProxyMixIn.java
    logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/JacksonFactory.java
    logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/XmlLayout.java
    logging/log4j/log4j2/trunk/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractJdbcAppenderTest.java
    logging/log4j/log4j2/trunk/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/AbstractJpaAppenderTest.java
    logging/log4j/log4j2/trunk/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/JpaHyperSqlAppenderTest.java
    logging/log4j/log4j2/trunk/log4j-core/src/test/java/org/apache/logging/log4j/core/net/SocketReconnectTest.java
    logging/log4j/log4j2/trunk/log4j-core/src/test/java/org/apache/logging/log4j/core/net/SocketTest.java
    logging/log4j/log4j2/trunk/log4j-core/src/test/java/org/apache/logging/log4j/core/net/server/AbstractSocketServerTest.java
    logging/log4j/log4j2/trunk/log4j-core/src/test/java/org/apache/logging/log4j/core/net/server/UdpJsonSocketServerTest.java
    logging/log4j/log4j2/trunk/log4j-core/src/test/java/org/apache/logging/log4j/core/net/server/UdpSerializedSocketServerTest.java
    logging/log4j/log4j2/trunk/log4j-core/src/test/java/org/apache/logging/log4j/core/net/server/UdpXmlSocketServerTest.java

Modified: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/ConnectionSource.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/ConnectionSource.java?rev=1596658&r1=1596657&r2=1596658&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/ConnectionSource.java (original)
+++ logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/ConnectionSource.java Wed May 21 19:37:09 2014
@@ -20,7 +20,7 @@ import java.sql.Connection;
 import java.sql.SQLException;
 
 /**
- * Configuration element for {@link JDBCAppender}. If you want to use the {@link JDBCAppender} but none of the provided
+ * Configuration element for {@link JdbcAppender}. If you want to use the {@link JdbcAppender} but none of the provided
  * connection sources meet your needs, you can simply create your own connection source.
  */
 public interface ConnectionSource {

Modified: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/DataSourceConnectionSource.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/DataSourceConnectionSource.java?rev=1596658&r1=1596657&r2=1596658&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/DataSourceConnectionSource.java (original)
+++ logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/DataSourceConnectionSource.java Wed May 21 19:37:09 2014
@@ -31,7 +31,7 @@ import org.apache.logging.log4j.status.S
 import org.apache.logging.log4j.util.Strings;
 
 /**
- * A {@link JDBCAppender} connection source that uses a {@link DataSource} to connect to the database.
+ * A {@link JdbcAppender} connection source that uses a {@link DataSource} to connect to the database.
  */
 @Plugin(name = "DataSource", category = "Core", elementType = "connectionSource", printObject = true)
 public final class DataSourceConnectionSource implements ConnectionSource {

Modified: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/FactoryMethodConnectionSource.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/FactoryMethodConnectionSource.java?rev=1596658&r1=1596657&r2=1596658&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/FactoryMethodConnectionSource.java (original)
+++ logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/FactoryMethodConnectionSource.java Wed May 21 19:37:09 2014
@@ -32,7 +32,7 @@ import org.apache.logging.log4j.status.S
 import org.apache.logging.log4j.util.Strings;
 
 /**
- * A {@link JDBCAppender} connection source that uses a public static factory method to obtain a {@link Connection} or
+ * A {@link JdbcAppender} connection source that uses a public static factory method to obtain a {@link Connection} or
  * {@link DataSource}.
  */
 @Plugin(name = "ConnectionFactory", category = "Core", elementType = "connectionSource", printObject = true)

Added: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppender.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppender.java?rev=1596658&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppender.java (added)
+++ logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppender.java Wed May 21 19:37:09 2014
@@ -0,0 +1,103 @@
+/*
+ * 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.jdbc;
+
+import org.apache.logging.log4j.core.Filter;
+import org.apache.logging.log4j.core.appender.AbstractAppender;
+import org.apache.logging.log4j.core.appender.db.AbstractDatabaseAppender;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
+import org.apache.logging.log4j.core.config.plugins.PluginElement;
+import org.apache.logging.log4j.core.config.plugins.PluginFactory;
+import org.apache.logging.log4j.core.util.Booleans;
+
+/**
+ * This Appender writes logging events to a relational database using standard JDBC mechanisms. It takes a list of
+ * {@link ColumnConfig}s with which it determines how to save the event data into the appropriate columns in the table.
+ * A {@link ConnectionSource} plugin instance instructs the appender (and {@link JdbcDatabaseManager}) how to connect to
+ * the database. This appender can be reconfigured at run time.
+ *
+ * @see ColumnConfig
+ * @see ConnectionSource
+ */
+@Plugin(name = "JDBC", category = "Core", elementType = "appender", printObject = true)
+public final class JdbcAppender extends AbstractDatabaseAppender<JdbcDatabaseManager> {
+    private final String description;
+
+    private JdbcAppender(final String name, final Filter filter, final boolean ignoreExceptions,
+                         final JdbcDatabaseManager manager) {
+        super(name, filter, ignoreExceptions, manager);
+        this.description = this.getName() + "{ manager=" + this.getManager() + " }";
+    }
+
+    @Override
+    public String toString() {
+        return this.description;
+    }
+
+    /**
+     * Factory method for creating a JDBC appender within the plugin manager.
+     *
+     * @param name The name of the appender.
+     * @param ignore If {@code "true"} (default) exceptions encountered when appending events are logged; otherwise
+     *               they are propagated to the caller.
+     * @param filter The filter, if any, to use.
+     * @param connectionSource The connections source from which database connections should be retrieved.
+     * @param bufferSize If an integer greater than 0, this causes the appender to buffer log events and flush whenever
+     *                   the buffer reaches this size.
+     * @param tableName The name of the database table to insert log events into.
+     * @param columnConfigs Information about the columns that log event data should be inserted into and how to insert
+     *                      that data.
+     * @return a new JDBC appender.
+     */
+    @PluginFactory
+    public static JdbcAppender createAppender(
+            @PluginAttribute("name") final String name,
+            @PluginAttribute("ignoreExceptions") final String ignore,
+            @PluginElement("Filter") final Filter filter,
+            @PluginElement("ConnectionSource") final ConnectionSource connectionSource,
+            @PluginAttribute("bufferSize") final String bufferSize,
+            @PluginAttribute("tableName") final String tableName,
+            @PluginElement("ColumnConfigs") final ColumnConfig[] columnConfigs) {
+
+        final int bufferSizeInt = AbstractAppender.parseInt(bufferSize, 0);
+        final boolean ignoreExceptions = Booleans.parseBoolean(ignore, true);
+
+        final StringBuilder managerName = new StringBuilder("jdbcManager{ description=").append(name)
+                .append(", bufferSize=").append(bufferSizeInt).append(", connectionSource=")
+                .append(connectionSource.toString()).append(", tableName=").append(tableName).append(", columns=[ ");
+
+        int i = 0;
+        for (final ColumnConfig column : columnConfigs) {
+            if (i++ > 0) {
+                managerName.append(", ");
+            }
+            managerName.append(column.toString());
+        }
+
+        managerName.append(" ] }");
+
+        final JdbcDatabaseManager manager = JdbcDatabaseManager.getJDBCDatabaseManager(
+                managerName.toString(), bufferSizeInt, connectionSource, tableName, columnConfigs
+        );
+        if (manager == null) {
+            return null;
+        }
+
+        return new JdbcAppender(name, filter, ignoreExceptions, manager);
+    }
+}

Propchange: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppender.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppender.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcDatabaseManager.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcDatabaseManager.java?rev=1596658&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcDatabaseManager.java (added)
+++ logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcDatabaseManager.java Wed May 21 19:37:09 2014
@@ -0,0 +1,244 @@
+/*
+ * 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.jdbc;
+
+import java.io.StringReader;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.appender.AppenderLoggingException;
+import org.apache.logging.log4j.core.appender.ManagerFactory;
+import org.apache.logging.log4j.core.appender.db.AbstractDatabaseManager;
+import org.apache.logging.log4j.core.layout.PatternLayout;
+import org.apache.logging.log4j.core.util.Closer;
+
+/**
+ * An {@link AbstractDatabaseManager} implementation for relational databases accessed via JDBC.
+ */
+public final class JdbcDatabaseManager extends AbstractDatabaseManager {
+    private static final JDBCDatabaseManagerFactory FACTORY = new JDBCDatabaseManagerFactory();
+
+    private final List<Column> columns;
+    private final ConnectionSource connectionSource;
+    private final String sqlStatement;
+
+    private Connection connection;
+    private PreparedStatement statement;
+
+    private JdbcDatabaseManager(final String name, final int bufferSize, final ConnectionSource connectionSource,
+                                final String sqlStatement, final List<Column> columns) {
+        super(name, bufferSize);
+        this.connectionSource = connectionSource;
+        this.sqlStatement = sqlStatement;
+        this.columns = columns;
+    }
+
+    @Override
+    protected void startupInternal() {
+        // nothing to see here
+    }
+
+    @Override
+    protected void shutdownInternal() {
+        if (this.connection != null || this.statement != null) {
+            this.commitAndClose();
+        }
+    }
+
+    @Override
+    protected void connectAndStart() {
+        try {
+            this.connection = this.connectionSource.getConnection();
+            this.connection.setAutoCommit(false);
+            this.statement = this.connection.prepareStatement(this.sqlStatement);
+        } catch (SQLException e) {
+            throw new AppenderLoggingException(
+                    "Cannot write logging event or flush buffer; JDBC manager cannot connect to the database.", e
+            );
+        }
+    }
+
+    @Override
+    protected void writeInternal(final LogEvent event) {
+        StringReader reader = null;
+        try {
+            if (!this.isRunning() || this.connection == null || this.connection.isClosed() || this.statement == null
+                    || this.statement.isClosed()) {
+                throw new AppenderLoggingException(
+                        "Cannot write logging event; JDBC manager not connected to the database.");
+            }
+
+            int i = 1;
+            for (final Column column : this.columns) {
+                if (column.isEventTimestamp) {
+                    this.statement.setTimestamp(i++, new Timestamp(event.getTimeMillis()));
+                } else {
+                    if (column.isClob) {
+                        reader = new StringReader(column.layout.toSerializable(event));
+                        if (column.isUnicode) {
+                            this.statement.setNClob(i++, reader);
+                        } else {
+                            this.statement.setClob(i++, reader);
+                        }
+                    } else {
+                        if (column.isUnicode) {
+                            this.statement.setNString(i++, column.layout.toSerializable(event));
+                        } else {
+                            this.statement.setString(i++, column.layout.toSerializable(event));
+                        }
+                    }
+                }
+            }
+
+            if (this.statement.executeUpdate() == 0) {
+                throw new AppenderLoggingException(
+                        "No records inserted in database table for log event in JDBC manager.");
+            }
+        } catch (final SQLException e) {
+            throw new AppenderLoggingException("Failed to insert record for log event in JDBC manager: " +
+                    e.getMessage(), e);
+        } finally {
+            Closer.closeSilent(reader);
+        }
+    }
+
+    @Override
+    protected void commitAndClose() {
+        try {
+            if (this.connection != null && !this.connection.isClosed()) {
+                this.connection.commit();
+            }
+        } catch (SQLException e) {
+            throw new AppenderLoggingException("Failed to commit transaction logging event or flushing buffer.", e);
+        } finally {
+            try {
+                if (this.statement != null) {
+                    this.statement.close();
+                }
+            } catch (Exception e) {
+                LOGGER.warn("Failed to close SQL statement logging event or flushing buffer.", e);
+            } finally {
+                this.statement = null;
+            }
+
+            try {
+                if (this.connection != null) {
+                    this.connection.close();
+                }
+            } catch (Exception e) {
+                LOGGER.warn("Failed to close database connection logging event or flushing buffer.", e);
+            } finally {
+                this.connection = null;
+            }
+        }
+    }
+
+    /**
+     * Creates a JDBC manager for use within the {@link JdbcAppender}, or returns a suitable one if it already exists.
+     *
+     * @param name The name of the manager, which should include connection details and hashed passwords where possible.
+     * @param bufferSize The size of the log event buffer.
+     * @param connectionSource The source for connections to the database.
+     * @param tableName The name of the database table to insert log events into.
+     * @param columnConfigs Configuration information about the log table columns.
+     * @return a new or existing JDBC manager as applicable.
+     */
+    public static JdbcDatabaseManager getJDBCDatabaseManager(final String name, final int bufferSize,
+                                                             final ConnectionSource connectionSource,
+                                                             final String tableName,
+                                                             final ColumnConfig[] columnConfigs) {
+
+        return AbstractDatabaseManager.getManager(
+                name, new FactoryData(bufferSize, connectionSource, tableName, columnConfigs), FACTORY
+        );
+    }
+
+    /**
+     * Encapsulates data that {@link JDBCDatabaseManagerFactory} uses to create managers.
+     */
+    private static final class FactoryData extends AbstractDatabaseManager.AbstractFactoryData {
+        private final ColumnConfig[] columnConfigs;
+        private final ConnectionSource connectionSource;
+        private final String tableName;
+
+        protected FactoryData(final int bufferSize, final ConnectionSource connectionSource, final String tableName,
+                              final ColumnConfig[] columnConfigs) {
+            super(bufferSize);
+            this.connectionSource = connectionSource;
+            this.tableName = tableName;
+            this.columnConfigs = columnConfigs;
+        }
+    }
+
+    /**
+     * Creates managers.
+     */
+    private static final class JDBCDatabaseManagerFactory implements ManagerFactory<JdbcDatabaseManager, FactoryData> {
+        @Override
+        public JdbcDatabaseManager createManager(final String name, final FactoryData data) {
+            final StringBuilder columnPart = new StringBuilder();
+            final StringBuilder valuePart = new StringBuilder();
+            final List<Column> columns = new ArrayList<Column>();
+            int i = 0;
+            for (final ColumnConfig config : data.columnConfigs) {
+                if (i++ > 0) {
+                    columnPart.append(',');
+                    valuePart.append(',');
+                }
+
+                columnPart.append(config.getColumnName());
+
+                if (config.getLiteralValue() != null) {
+                    valuePart.append(config.getLiteralValue());
+                } else {
+                    columns.add(new Column(
+                            config.getLayout(), config.isEventTimestamp(), config.isUnicode(), config.isClob()
+                    ));
+                    valuePart.append('?');
+                }
+            }
+
+            final String sqlStatement = "INSERT INTO " + data.tableName + " (" + columnPart + ") VALUES (" +
+                    valuePart + ')';
+
+            return new JdbcDatabaseManager(name, data.getBufferSize(), data.connectionSource, sqlStatement, columns);
+        }
+    }
+
+    /**
+     * Encapsulates information about a database column and how to persist data to it.
+     */
+    private static final class Column {
+        private final PatternLayout layout;
+        private final boolean isEventTimestamp;
+        private final boolean isUnicode;
+        private final boolean isClob;
+
+        private Column(final PatternLayout layout, final boolean isEventDate, final boolean isUnicode,
+                       final boolean isClob) {
+            this.layout = layout;
+            this.isEventTimestamp = isEventDate;
+            this.isUnicode = isUnicode;
+            this.isClob = isClob;
+        }
+    }
+}

Propchange: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcDatabaseManager.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcDatabaseManager.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/JpaAppender.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/JpaAppender.java?rev=1596658&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/JpaAppender.java (added)
+++ logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/JpaAppender.java Wed May 21 19:37:09 2014
@@ -0,0 +1,126 @@
+/*
+ * 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;
+
+import java.lang.reflect.Constructor;
+
+import org.apache.logging.log4j.core.Filter;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.appender.AbstractAppender;
+import org.apache.logging.log4j.core.appender.db.AbstractDatabaseAppender;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
+import org.apache.logging.log4j.core.config.plugins.PluginElement;
+import org.apache.logging.log4j.core.config.plugins.PluginFactory;
+import org.apache.logging.log4j.core.util.Booleans;
+import org.apache.logging.log4j.core.util.Loader;
+import org.apache.logging.log4j.util.Strings;
+
+/**
+ * This Appender writes logging events to a relational database using the Java Persistence API. It requires a
+ * pre-configured JPA persistence unit and a concrete implementation of the abstract
+ * {@link AbstractLogEventWrapperEntity} class decorated with JPA annotations.
+ *
+ * @see AbstractLogEventWrapperEntity
+ */
+@Plugin(name = "JPA", category = "Core", elementType = "appender", printObject = true)
+public final class JpaAppender extends AbstractDatabaseAppender<JpaDatabaseManager> {
+    private final String description;
+
+    private JpaAppender(final String name, final Filter filter, final boolean ignoreExceptions,
+            final JpaDatabaseManager manager) {
+        super(name, filter, ignoreExceptions, manager);
+        this.description = this.getName() + "{ manager=" + this.getManager() + " }";
+    }
+
+    @Override
+    public String toString() {
+        return this.description;
+    }
+
+    /**
+     * Factory method for creating a JPA appender within the plugin manager.
+     *
+     * @param name The name of the appender.
+     * @param ignore If {@code "true"} (default) exceptions encountered when appending events are logged; otherwise
+     *               they are propagated to the caller.
+     * @param filter The filter, if any, to use.
+     * @param bufferSize If an integer greater than 0, this causes the appender to buffer log events and flush whenever
+     *                   the buffer reaches this size.
+     * @param entityClassName The fully qualified name of the concrete {@link AbstractLogEventWrapperEntity}
+     *                        implementation that has JPA annotations mapping it to a database table.
+     * @param persistenceUnitName The name of the JPA persistence unit that should be used for persisting log events.
+     * @return a new JPA appender.
+     */
+    @PluginFactory
+    public static JpaAppender createAppender(
+            @PluginAttribute("name") final String name,
+            @PluginAttribute("ignoreExceptions") final String ignore,
+            @PluginElement("Filter") final Filter filter,
+            @PluginAttribute("bufferSize") final String bufferSize,
+            @PluginAttribute("entityClassName") final String entityClassName,
+            @PluginAttribute("persistenceUnitName") final String persistenceUnitName) {
+        if (Strings.isEmpty(entityClassName) || Strings.isEmpty(persistenceUnitName)) {
+            LOGGER.error("Attributes entityClassName and persistenceUnitName are required for JPA Appender.");
+            return null;
+        }
+
+        final int bufferSizeInt = AbstractAppender.parseInt(bufferSize, 0);
+        final boolean ignoreExceptions = Booleans.parseBoolean(ignore, true);
+
+        try {
+            @SuppressWarnings("unchecked")
+            final Class<? extends AbstractLogEventWrapperEntity> entityClass =
+                    (Class<? extends AbstractLogEventWrapperEntity>) Loader.loadClass(entityClassName);
+
+            if (!AbstractLogEventWrapperEntity.class.isAssignableFrom(entityClass)) {
+                LOGGER.error("Entity class [{}] does not extend AbstractLogEventWrapperEntity.", entityClassName);
+                return null;
+            }
+
+            try {
+                entityClass.getConstructor();
+            } catch (final NoSuchMethodException e) {
+                LOGGER.error("Entity class [{}] does not have a no-arg constructor. The JPA provider will reject it.",
+                        entityClassName);
+                return null;
+            }
+
+            final Constructor<? extends AbstractLogEventWrapperEntity> entityConstructor =
+                    entityClass.getConstructor(LogEvent.class);
+
+            final String managerName = "jpaManager{ description=" + name + ", bufferSize=" + bufferSizeInt
+                    + ", persistenceUnitName=" + persistenceUnitName + ", entityClass=" + entityClass.getName() + '}';
+
+            final JpaDatabaseManager manager = JpaDatabaseManager.getJPADatabaseManager(
+                    managerName, bufferSizeInt, entityClass, entityConstructor, persistenceUnitName
+            );
+            if (manager == null) {
+                return null;
+            }
+
+            return new JpaAppender(name, filter, ignoreExceptions, manager);
+        } catch (final ClassNotFoundException e) {
+            LOGGER.error("Could not load entity class [{}].", entityClassName, e);
+            return null;
+        } catch (final NoSuchMethodException e) {
+            LOGGER.error("Entity class [{}] does not have a constructor with a single argument of type LogEvent.",
+                    entityClassName);
+            return null;
+        }
+    }
+}

Propchange: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/JpaAppender.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/JpaAppender.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/JpaDatabaseManager.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/JpaDatabaseManager.java?rev=1596658&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/JpaDatabaseManager.java (added)
+++ logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/JpaDatabaseManager.java Wed May 21 19:37:09 2014
@@ -0,0 +1,188 @@
+/*
+ * 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;
+
+import java.lang.reflect.Constructor;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.EntityTransaction;
+import javax.persistence.Persistence;
+
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.appender.AppenderLoggingException;
+import org.apache.logging.log4j.core.appender.ManagerFactory;
+import org.apache.logging.log4j.core.appender.db.AbstractDatabaseManager;
+
+/**
+ * An {@link AbstractDatabaseManager} implementation for relational databases accessed via JPA.
+ */
+public final class JpaDatabaseManager extends AbstractDatabaseManager {
+    private static final JPADatabaseManagerFactory FACTORY = new JPADatabaseManagerFactory();
+
+    private final String entityClassName;
+    private final Constructor<? extends AbstractLogEventWrapperEntity> entityConstructor;
+    private final String persistenceUnitName;
+
+    private EntityManagerFactory entityManagerFactory;
+
+    private EntityManager entityManager;
+    private EntityTransaction transaction;
+
+    private JpaDatabaseManager(final String name, final int bufferSize,
+                               final Class<? extends AbstractLogEventWrapperEntity> entityClass,
+                               final Constructor<? extends AbstractLogEventWrapperEntity> entityConstructor,
+                               final String persistenceUnitName) {
+        super(name, bufferSize);
+        this.entityClassName = entityClass.getName();
+        this.entityConstructor = entityConstructor;
+        this.persistenceUnitName = persistenceUnitName;
+    }
+
+    @Override
+    protected void startupInternal() {
+        this.entityManagerFactory = Persistence.createEntityManagerFactory(this.persistenceUnitName);
+    }
+
+    @Override
+    protected void shutdownInternal() {
+        if (this.entityManager != null || this.transaction != null) {
+            this.commitAndClose();
+        }
+        if (this.entityManagerFactory != null && this.entityManagerFactory.isOpen()) {
+            this.entityManagerFactory.close();
+        }
+    }
+
+    @Override
+    protected void connectAndStart() {
+        try {
+            this.entityManager = this.entityManagerFactory.createEntityManager();
+            this.transaction = this.entityManager.getTransaction();
+            this.transaction.begin();
+        } catch (Exception e) {
+            throw new AppenderLoggingException(
+                    "Cannot write logging event or flush buffer; manager cannot create EntityManager or transaction.", e
+            );
+        }
+    }
+
+    @Override
+    protected void writeInternal(final LogEvent event) {
+        if (!this.isRunning() || this.entityManagerFactory == null || this.entityManager == null
+                || this.transaction == null) {
+            throw new AppenderLoggingException(
+                    "Cannot write logging event; JPA manager not connected to the database.");
+        }
+
+        AbstractLogEventWrapperEntity entity;
+        try {
+            entity = this.entityConstructor.newInstance(event);
+        } catch (final Exception e) {
+            throw new AppenderLoggingException("Failed to instantiate entity class [" + this.entityClassName + "].", e);
+        }
+
+        try {
+            this.entityManager.persist(entity);
+        } catch (final Exception e) {
+            if (this.transaction != null && this.transaction.isActive()) {
+                this.transaction.rollback();
+                this.transaction = null;
+            }
+            throw new AppenderLoggingException("Failed to insert record for log event in JPA manager: " +
+                    e.getMessage(), e);
+        }
+    }
+
+    @Override
+    protected void commitAndClose() {
+        try {
+            if (this.transaction != null && this.transaction.isActive()) {
+                this.transaction.commit();
+            }
+        } catch (Exception e) {
+            if (this.transaction != null && this.transaction.isActive()) {
+                this.transaction.rollback();
+            }
+        } finally {
+            this.transaction = null;
+            try {
+                if (this.entityManager != null && this.entityManager.isOpen()) {
+                    this.entityManager.close();
+                }
+            } catch (Exception e) {
+                LOGGER.warn("Failed to close entity manager while logging event or flushing buffer.", e);
+            } finally {
+                this.entityManager = null;
+            }
+        }
+    }
+
+    /**
+     * Creates a JPA manager for use within the {@link JpaAppender}, or returns a suitable one if it already exists.
+     *
+     * @param name The name of the manager, which should include connection details, entity class name, etc.
+     * @param bufferSize The size of the log event buffer.
+     * @param entityClass The fully-qualified class name of the {@link AbstractLogEventWrapperEntity} concrete
+     *                    implementation.
+     * @param entityConstructor The one-arg {@link LogEvent} constructor for the concrete entity class.
+     * @param persistenceUnitName The name of the JPA persistence unit that should be used for persisting log events.
+     * @return a new or existing JPA manager as applicable.
+     */
+    public static JpaDatabaseManager getJPADatabaseManager(final String name, final int bufferSize,
+                                                           final Class<? extends AbstractLogEventWrapperEntity>
+                                                                   entityClass,
+                                                           final Constructor<? extends AbstractLogEventWrapperEntity>
+                                                                   entityConstructor,
+                                                           final String persistenceUnitName) {
+
+        return AbstractDatabaseManager.getManager(
+                name, new FactoryData(bufferSize, entityClass, entityConstructor, persistenceUnitName), FACTORY
+        );
+    }
+
+    /**
+     * Encapsulates data that {@link JPADatabaseManagerFactory} uses to create managers.
+     */
+    private static final class FactoryData extends AbstractDatabaseManager.AbstractFactoryData {
+        private final Class<? extends AbstractLogEventWrapperEntity> entityClass;
+        private final Constructor<? extends AbstractLogEventWrapperEntity> entityConstructor;
+        private final String persistenceUnitName;
+
+        protected FactoryData(final int bufferSize, final Class<? extends AbstractLogEventWrapperEntity> entityClass,
+                              final Constructor<? extends AbstractLogEventWrapperEntity> entityConstructor,
+                              final String persistenceUnitName) {
+            super(bufferSize);
+
+            this.entityClass = entityClass;
+            this.entityConstructor = entityConstructor;
+            this.persistenceUnitName = persistenceUnitName;
+        }
+    }
+
+    /**
+     * Creates managers.
+     */
+    private static final class JPADatabaseManagerFactory implements ManagerFactory<JpaDatabaseManager, FactoryData> {
+        @Override
+        public JpaDatabaseManager createManager(final String name, final FactoryData data) {
+            return new JpaDatabaseManager(
+                    name, data.getBufferSize(), data.entityClass, data.entityConstructor, data.persistenceUnitName
+            );
+        }
+    }
+}

Propchange: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/JpaDatabaseManager.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/JpaDatabaseManager.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/JsonConstants.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/JsonConstants.java?rev=1596658&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/JsonConstants.java (added)
+++ logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/JsonConstants.java Wed May 21 19:37:09 2014
@@ -0,0 +1,33 @@
+/*
+ * 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.jackson;
+
+/**
+ * Keeps constants separate from any class that may depend on third party jars.
+ */
+public final class JsonConstants {
+    public static final String ELT_CAUSE = "cause";
+    public static final String ELT_CONTEXT_MAP = "contextMap";
+    public static final String ELT_CONTEXT_STACK = "contextStack";
+    public static final String ELT_MARKER = "marker";
+    public static final String ELT_PARENTS = "parents";
+    public static final String ELT_SOURCE = "source";
+    public static final String ELT_SUPPRESSED = "suppressed";
+    public static final String ELT_THROWN = "thrown";
+    public static final String ELT_MESSAGE = "message";
+    public static final String ELT_EXTENDED_STACK_TRACE = "extendedStackTrace";
+}

Propchange: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/JsonConstants.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/JsonConstants.java
------------------------------------------------------------------------------
    svn:keywords = Id

Modified: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/LogEventMixIn.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/LogEventMixIn.java?rev=1596658&r1=1596657&r2=1596658&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/LogEventMixIn.java (original)
+++ logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/LogEventMixIn.java Wed May 21 19:37:09 2014
@@ -36,25 +36,25 @@ import com.fasterxml.jackson.dataformat.
 import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
 import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
 
-@JsonRootName(XMLConstants.ELT_EVENT)
-@JacksonXmlRootElement(namespace = XMLConstants.XML_NAMESPACE, localName = XMLConstants.ELT_EVENT)
+@JsonRootName(XmlConstants.ELT_EVENT)
+@JacksonXmlRootElement(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_EVENT)
 @JsonFilter("org.apache.logging.log4j.core.impl.Log4jLogEvent")
-@JsonPropertyOrder({ "timeMillis", "threadName", "level", "loggerName", "marker", "message", "thrown", XMLConstants.ELT_CONTEXT_MAP,
-        JSONConstants.ELT_CONTEXT_STACK, "loggerFQCN", "Source", "endOfBatch" })
+@JsonPropertyOrder({ "timeMillis", "threadName", "level", "loggerName", "marker", "message", "thrown", XmlConstants.ELT_CONTEXT_MAP,
+        JsonConstants.ELT_CONTEXT_STACK, "loggerFQCN", "Source", "endOfBatch" })
 abstract class LogEventMixIn implements LogEvent {
 
     private static final long serialVersionUID = 1L;
 
-    @JsonProperty(JSONConstants.ELT_CONTEXT_MAP)
-    @JacksonXmlProperty(namespace = XMLConstants.XML_NAMESPACE, localName = XMLConstants.ELT_CONTEXT_MAP)
+    @JsonProperty(JsonConstants.ELT_CONTEXT_MAP)
+    @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_CONTEXT_MAP)
     @JsonSerialize(using = ListOfMapEntrySerializer.class)
     @JsonDeserialize(using = ListOfMapEntryDeserializer.class)
     @Override
     public abstract Map<String, String> getContextMap();
 
-    @JsonProperty(JSONConstants.ELT_CONTEXT_STACK)
-    @JacksonXmlElementWrapper(namespace = XMLConstants.XML_NAMESPACE, localName = XMLConstants.ELT_CONTEXT_STACK)
-    @JacksonXmlProperty(namespace = XMLConstants.XML_NAMESPACE, localName = XMLConstants.ELT_CONTEXT_STACK_ITEM)
+    @JsonProperty(JsonConstants.ELT_CONTEXT_STACK)
+    @JacksonXmlElementWrapper(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_CONTEXT_STACK)
+    @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_CONTEXT_STACK_ITEM)
     @Override
     public abstract ContextStack getContextStack();
 
@@ -73,21 +73,21 @@ abstract class LogEventMixIn implements 
     @Override
     public abstract String getLoggerName();
 
-    @JsonProperty(JSONConstants.ELT_MARKER)
-    @JacksonXmlProperty(namespace = XMLConstants.XML_NAMESPACE, localName = XMLConstants.ELT_MARKER)
+    @JsonProperty(JsonConstants.ELT_MARKER)
+    @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_MARKER)
     @Override
     public abstract Marker getMarker();
 
-    @JsonProperty(JSONConstants.ELT_MESSAGE)
+    @JsonProperty(JsonConstants.ELT_MESSAGE)
     @JsonSerialize(using = MessageSerializer.class)
     @JsonDeserialize(using = SimpleMessageDeserializer.class)
-    @JacksonXmlProperty(namespace = XMLConstants.XML_NAMESPACE, localName = XMLConstants.ELT_MESSAGE)
+    @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_MESSAGE)
     @Override
     public abstract Message getMessage();
 
-    @JsonProperty(JSONConstants.ELT_SOURCE)
+    @JsonProperty(JsonConstants.ELT_SOURCE)
     @JsonDeserialize(using = Log4jStackTraceElementDeserializer.class)
-    @JacksonXmlProperty(namespace = XMLConstants.XML_NAMESPACE, localName = XMLConstants.ELT_SOURCE)
+    @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_SOURCE)
     @Override
     public abstract StackTraceElement getSource();
 
@@ -100,8 +100,8 @@ abstract class LogEventMixIn implements 
     @Override
     public abstract Throwable getThrown();
 
-    @JsonProperty(JSONConstants.ELT_THROWN)
-    @JacksonXmlProperty(namespace = XMLConstants.XML_NAMESPACE, localName = XMLConstants.ELT_THROWN)
+    @JsonProperty(JsonConstants.ELT_THROWN)
+    @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_THROWN)
     @Override
     public abstract ThrowableProxy getThrownProxy();
 

Modified: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/MarkerMixIn.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/MarkerMixIn.java?rev=1596658&r1=1596657&r2=1596658&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/MarkerMixIn.java (original)
+++ logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/MarkerMixIn.java Wed May 21 19:37:09 2014
@@ -72,9 +72,9 @@ abstract class MarkerMixIn implements Ma
     public abstract Marker getParent();
 
     @Override
-    @JsonProperty(JSONConstants.ELT_PARENTS)
-    @JacksonXmlElementWrapper(namespace = XMLConstants.XML_NAMESPACE, localName = XMLConstants.ELT_PARENTS)
-    @JacksonXmlProperty(namespace = XMLConstants.XML_NAMESPACE, localName = XMLConstants.ELT_MARKER)
+    @JsonProperty(JsonConstants.ELT_PARENTS)
+    @JacksonXmlElementWrapper(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_PARENTS)
+    @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_MARKER)
     public abstract Marker[] getParents();
 
 }

Modified: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ThrowableProxyMixIn.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ThrowableProxyMixIn.java?rev=1596658&r1=1596657&r2=1596658&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ThrowableProxyMixIn.java (original)
+++ logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ThrowableProxyMixIn.java Wed May 21 19:37:09 2014
@@ -29,17 +29,17 @@ import com.fasterxml.jackson.dataformat.
  */
 abstract class ThrowableProxyMixIn {
 
-    @JsonProperty(JSONConstants.ELT_CAUSE)
-    @JacksonXmlProperty(namespace = XMLConstants.XML_NAMESPACE, localName = XMLConstants.ELT_CAUSE)
+    @JsonProperty(JsonConstants.ELT_CAUSE)
+    @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_CAUSE)
     private ThrowableProxyMixIn causeProxy;
 
     @JsonProperty
     @JacksonXmlProperty(isAttribute = true)
     private int commonElementCount;
 
-    @JsonProperty(JSONConstants.ELT_EXTENDED_STACK_TRACE)
-    @JacksonXmlElementWrapper(namespace = XMLConstants.XML_NAMESPACE, localName = XMLConstants.ELT_EXTENDED_STACK_TRACE)
-    @JacksonXmlProperty(namespace = XMLConstants.XML_NAMESPACE, localName = XMLConstants.ELT_EXTENDED_STACK_TRACE_ITEM)
+    @JsonProperty(JsonConstants.ELT_EXTENDED_STACK_TRACE)
+    @JacksonXmlElementWrapper(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_EXTENDED_STACK_TRACE)
+    @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_EXTENDED_STACK_TRACE_ITEM)
     private ExtendedStackTraceElement[] extendedStackTrace;
 
     @JsonProperty
@@ -66,9 +66,9 @@ abstract class ThrowableProxyMixIn {
     @JsonIgnore
     public abstract StackTraceElement[] getStackTrace();
 
-    @JsonProperty(JSONConstants.ELT_SUPPRESSED)
-    @JacksonXmlElementWrapper(namespace = XMLConstants.XML_NAMESPACE, localName = XMLConstants.ELT_SUPPRESSED)
-    @JacksonXmlProperty(namespace = XMLConstants.XML_NAMESPACE, localName = XMLConstants.ELT_SUPPRESSED_ITEM)
+    @JsonProperty(JsonConstants.ELT_SUPPRESSED)
+    @JacksonXmlElementWrapper(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_SUPPRESSED)
+    @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_SUPPRESSED_ITEM)
     public abstract ThrowableProxy[] getSuppressedProxies();
 
     @JsonIgnore

Added: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/XmlConstants.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/XmlConstants.java?rev=1596658&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/XmlConstants.java (added)
+++ logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/XmlConstants.java Wed May 21 19:37:09 2014
@@ -0,0 +1,38 @@
+/*
+ * 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.jackson;
+
+/**
+ * Keeps constants separate from any class that may depend on third party jars.
+ */
+public final class XmlConstants {
+    public static final String ELT_CAUSE = "Cause";
+    public static final String ELT_CONTEXT_MAP = "ContextMap";
+    public static final String ELT_CONTEXT_STACK = "ContextStack";
+    public static final String ELT_CONTEXT_STACK_ITEM = "ContextStackItem";
+    public static final String ELT_EVENT = "Event";
+    public static final String ELT_EXTENDED_STACK_TRACE = "ExtendedStackTrace";
+    public static final String ELT_EXTENDED_STACK_TRACE_ITEM = "ExtendedStackTraceItem";
+    public static final String ELT_MARKER = "Marker";
+    public static final String ELT_MESSAGE = "Message";
+    public static final String ELT_PARENTS = "Parents";
+    public static final String ELT_SOURCE = "Source";
+    public static final String ELT_SUPPRESSED = "Suppressed";
+    public static final String ELT_SUPPRESSED_ITEM = "SuppressedItem";
+    public static final String ELT_THROWN = "Thrown";
+    public static final String XML_NAMESPACE = "http://logging.apache.org/log4j/2.0/events";
+}

Propchange: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/XmlConstants.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/XmlConstants.java
------------------------------------------------------------------------------
    svn:keywords = Id

Modified: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/JacksonFactory.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/JacksonFactory.java?rev=1596658&r1=1596657&r2=1596658&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/JacksonFactory.java (original)
+++ logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/JacksonFactory.java Wed May 21 19:37:09 2014
@@ -20,10 +20,10 @@ import java.util.HashSet;
 import java.util.Set;
 
 import org.apache.logging.log4j.core.impl.Log4jLogEvent;
-import org.apache.logging.log4j.core.jackson.JSONConstants;
+import org.apache.logging.log4j.core.jackson.JsonConstants;
 import org.apache.logging.log4j.core.jackson.Log4jJsonObjectMapper;
 import org.apache.logging.log4j.core.jackson.Log4jXmlObjectMapper;
-import org.apache.logging.log4j.core.jackson.XMLConstants;
+import org.apache.logging.log4j.core.jackson.XmlConstants;
 
 import com.fasterxml.jackson.core.PrettyPrinter;
 import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
@@ -40,12 +40,12 @@ abstract class JacksonFactory {
 
         @Override
         protected String getPropertNameForContextMap() {
-            return JSONConstants.ELT_CONTEXT_MAP;
+            return JsonConstants.ELT_CONTEXT_MAP;
         }
 
         @Override
         protected String getPropertNameForSource() {
-            return JSONConstants.ELT_SOURCE;
+            return JsonConstants.ELT_SOURCE;
         }
 
         @Override
@@ -68,12 +68,12 @@ abstract class JacksonFactory {
 
         @Override
         protected String getPropertNameForContextMap() {
-            return XMLConstants.ELT_CONTEXT_MAP;
+            return XmlConstants.ELT_CONTEXT_MAP;
         }
 
         @Override
         protected String getPropertNameForSource() {
-            return XMLConstants.ELT_SOURCE;
+            return XmlConstants.ELT_SOURCE;
         }
 
         @Override

Added: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/JsonLayout.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/JsonLayout.java?rev=1596658&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/JsonLayout.java (added)
+++ logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/JsonLayout.java Wed May 21 19:37:09 2014
@@ -0,0 +1,871 @@
+/*
+ * 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.layout;
+
+import java.nio.charset.Charset;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
+import org.apache.logging.log4j.core.config.plugins.PluginFactory;
+import org.apache.logging.log4j.core.util.Charsets;
+
+/**
+ * Appends a series of JSON events as strings serialized as bytes.
+ * 
+ * <h4>Complete well-formed JSON vs. fragment JSON</h4>
+ * <p>
+ * If you configure {@code complete="true"}, the appender outputs a well-formed JSON document. By default, with {@code complete="false"},
+ * you should include the output as an <em>external file</em> in a separate file to form a well-formed JSON document.
+ * </p>
+ * <p>
+ * A well-formed JSON event follows this pattern:
+ * </p>
+ * 
+ * <pre>
+ * {
+  "timeMillis": 1,
+  "thread": "MyThreadName",
+  "level": "DEBUG",
+  "loggerName": "a.B",
+  "marker": {
+    "name": "Marker1",
+    "parents": [{
+      "name": "ParentMarker1",
+      "parents": [{
+        "name": "GrandMotherMarker"
+      }, {
+        "name": "GrandFatherMarker"
+      }]
+    }, {
+      "name": "GrandFatherMarker"
+    }]
+  },
+  "message": "Msg",
+  "thrown": {
+    "cause": {
+      "commonElementCount": 27,
+      "extendedStackTrace": [{
+        "class": "org.apache.logging.log4j.core.layout.LogEventFixtures",
+        "method": "createLogEvent",
+        "file": "LogEventFixtures.java",
+        "line": 53,
+        "exact": false,
+        "location": "test-classes/",
+        "version": "?"
+      }],
+      "localizedMessage": "testNPEx",
+      "message": "testNPEx",
+      "name": "java.lang.NullPointerException"
+    },
+    "commonElementCount": 0,
+    "extendedStackTrace": [{
+      "class": "org.apache.logging.log4j.core.layout.LogEventFixtures",
+      "method": "createLogEvent",
+      "file": "LogEventFixtures.java",
+      "line": 56,
+      "exact": true,
+      "location": "test-classes/",
+      "version": "?"
+    }, {
+      "class": "org.apache.logging.log4j.core.layout.JsonLayoutTest",
+      "method": "testAllFeatures",
+      "file": "JsonLayoutTest.java",
+      "line": 105,
+      "exact": true,
+      "location": "test-classes/",
+      "version": "?"
+    }, {
+      "class": "org.apache.logging.log4j.core.layout.JsonLayoutTest",
+      "method": "testLocationOnCompactOnMdcOn",
+      "file": "JsonLayoutTest.java",
+      "line": 268,
+      "exact": true,
+      "location": "test-classes/",
+      "version": "?"
+    }, {
+      "class": "sun.reflect.NativeMethodAccessorImpl",
+      "method": "invoke",
+      "line": -1,
+      "exact": false,
+      "location": "?",
+      "version": "1.7.0_55"
+    }, {
+      "class": "sun.reflect.NativeMethodAccessorImpl",
+      "method": "invoke",
+      "line": -1,
+      "exact": false,
+      "location": "?",
+      "version": "1.7.0_55"
+    }, {
+      "class": "sun.reflect.DelegatingMethodAccessorImpl",
+      "method": "invoke",
+      "line": -1,
+      "exact": false,
+      "location": "?",
+      "version": "1.7.0_55"
+    }, {
+      "class": "java.lang.reflect.Method",
+      "method": "invoke",
+      "line": -1,
+      "exact": false,
+      "location": "?",
+      "version": "1.7.0_55"
+    }, {
+      "class": "org.junit.runners.model.FrameworkMethod$1",
+      "method": "runReflectiveCall",
+      "file": "FrameworkMethod.java",
+      "line": 47,
+      "exact": true,
+      "location": "junit-4.11.jar",
+      "version": "?"
+    }, {
+      "class": "org.junit.internal.runners.model.ReflectiveCallable",
+      "method": "run",
+      "file": "ReflectiveCallable.java",
+      "line": 12,
+      "exact": true,
+      "location": "junit-4.11.jar",
+      "version": "?"
+    }, {
+      "class": "org.junit.runners.model.FrameworkMethod",
+      "method": "invokeExplosively",
+      "file": "FrameworkMethod.java",
+      "line": 44,
+      "exact": true,
+      "location": "junit-4.11.jar",
+      "version": "?"
+    }, {
+      "class": "org.junit.internal.runners.statements.InvokeMethod",
+      "method": "evaluate",
+      "file": "InvokeMethod.java",
+      "line": 17,
+      "exact": true,
+      "location": "junit-4.11.jar",
+      "version": "?"
+    }, {
+      "class": "org.junit.runners.ParentRunner",
+      "method": "runLeaf",
+      "file": "ParentRunner.java",
+      "line": 271,
+      "exact": true,
+      "location": "junit-4.11.jar",
+      "version": "?"
+    }, {
+      "class": "org.junit.runners.BlockJUnit4ClassRunner",
+      "method": "runChild",
+      "file": "BlockJUnit4ClassRunner.java",
+      "line": 70,
+      "exact": true,
+      "location": "junit-4.11.jar",
+      "version": "?"
+    }, {
+      "class": "org.junit.runners.BlockJUnit4ClassRunner",
+      "method": "runChild",
+      "file": "BlockJUnit4ClassRunner.java",
+      "line": 50,
+      "exact": true,
+      "location": "junit-4.11.jar",
+      "version": "?"
+    }, {
+      "class": "org.junit.runners.ParentRunner$3",
+      "method": "run",
+      "file": "ParentRunner.java",
+      "line": 238,
+      "exact": true,
+      "location": "junit-4.11.jar",
+      "version": "?"
+    }, {
+      "class": "org.junit.runners.ParentRunner$1",
+      "method": "schedule",
+      "file": "ParentRunner.java",
+      "line": 63,
+      "exact": true,
+      "location": "junit-4.11.jar",
+      "version": "?"
+    }, {
+      "class": "org.junit.runners.ParentRunner",
+      "method": "runChildren",
+      "file": "ParentRunner.java",
+      "line": 236,
+      "exact": true,
+      "location": "junit-4.11.jar",
+      "version": "?"
+    }, {
+      "class": "org.junit.runners.ParentRunner",
+      "method": "access$000",
+      "file": "ParentRunner.java",
+      "line": 53,
+      "exact": true,
+      "location": "junit-4.11.jar",
+      "version": "?"
+    }, {
+      "class": "org.junit.runners.ParentRunner$2",
+      "method": "evaluate",
+      "file": "ParentRunner.java",
+      "line": 229,
+      "exact": true,
+      "location": "junit-4.11.jar",
+      "version": "?"
+    }, {
+      "class": "org.junit.internal.runners.statements.RunBefores",
+      "method": "evaluate",
+      "file": "RunBefores.java",
+      "line": 26,
+      "exact": true,
+      "location": "junit-4.11.jar",
+      "version": "?"
+    }, {
+      "class": "org.junit.internal.runners.statements.RunAfters",
+      "method": "evaluate",
+      "file": "RunAfters.java",
+      "line": 27,
+      "exact": true,
+      "location": "junit-4.11.jar",
+      "version": "?"
+    }, {
+      "class": "org.junit.runners.ParentRunner",
+      "method": "run",
+      "file": "ParentRunner.java",
+      "line": 309,
+      "exact": true,
+      "location": "junit-4.11.jar",
+      "version": "?"
+    }, {
+      "class": "org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference",
+      "method": "run",
+      "file": "JUnit4TestReference.java",
+      "line": 50,
+      "exact": true,
+      "location": ".cp/",
+      "version": "?"
+    }, {
+      "class": "org.eclipse.jdt.internal.junit.runner.TestExecution",
+      "method": "run",
+      "file": "TestExecution.java",
+      "line": 38,
+      "exact": true,
+      "location": ".cp/",
+      "version": "?"
+    }, {
+      "class": "org.eclipse.jdt.internal.junit.runner.RemoteTestRunner",
+      "method": "runTests",
+      "file": "RemoteTestRunner.java",
+      "line": 467,
+      "exact": true,
+      "location": ".cp/",
+      "version": "?"
+    }, {
+      "class": "org.eclipse.jdt.internal.junit.runner.RemoteTestRunner",
+      "method": "runTests",
+      "file": "RemoteTestRunner.java",
+      "line": 683,
+      "exact": true,
+      "location": ".cp/",
+      "version": "?"
+    }, {
+      "class": "org.eclipse.jdt.internal.junit.runner.RemoteTestRunner",
+      "method": "run",
+      "file": "RemoteTestRunner.java",
+      "line": 390,
+      "exact": true,
+      "location": ".cp/",
+      "version": "?"
+    }, {
+      "class": "org.eclipse.jdt.internal.junit.runner.RemoteTestRunner",
+      "method": "main",
+      "file": "RemoteTestRunner.java",
+      "line": 197,
+      "exact": true,
+      "location": ".cp/",
+      "version": "?"
+    }],
+    "localizedMessage": "testIOEx",
+    "message": "testIOEx",
+    "name": "java.io.IOException",
+    "suppressed": [{
+      "commonElementCount": 0,
+      "extendedStackTrace": [{
+        "class": "org.apache.logging.log4j.core.layout.LogEventFixtures",
+        "method": "createLogEvent",
+        "file": "LogEventFixtures.java",
+        "line": 57,
+        "exact": true,
+        "location": "test-classes/",
+        "version": "?"
+      }, {
+        "class": "org.apache.logging.log4j.core.layout.JsonLayoutTest",
+        "method": "testAllFeatures",
+        "file": "JsonLayoutTest.java",
+        "line": 105,
+        "exact": true,
+        "location": "test-classes/",
+        "version": "?"
+      }, {
+        "class": "org.apache.logging.log4j.core.layout.JsonLayoutTest",
+        "method": "testLocationOnCompactOnMdcOn",
+        "file": "JsonLayoutTest.java",
+        "line": 268,
+        "exact": true,
+        "location": "test-classes/",
+        "version": "?"
+      }, {
+        "class": "sun.reflect.NativeMethodAccessorImpl",
+        "method": "invoke",
+        "line": -1,
+        "exact": false,
+        "location": "?",
+        "version": "1.7.0_55"
+      }, {
+        "class": "sun.reflect.NativeMethodAccessorImpl",
+        "method": "invoke",
+        "line": -1,
+        "exact": false,
+        "location": "?",
+        "version": "1.7.0_55"
+      }, {
+        "class": "sun.reflect.DelegatingMethodAccessorImpl",
+        "method": "invoke",
+        "line": -1,
+        "exact": false,
+        "location": "?",
+        "version": "1.7.0_55"
+      }, {
+        "class": "java.lang.reflect.Method",
+        "method": "invoke",
+        "line": -1,
+        "exact": false,
+        "location": "?",
+        "version": "1.7.0_55"
+      }, {
+        "class": "org.junit.runners.model.FrameworkMethod$1",
+        "method": "runReflectiveCall",
+        "file": "FrameworkMethod.java",
+        "line": 47,
+        "exact": true,
+        "location": "junit-4.11.jar",
+        "version": "?"
+      }, {
+        "class": "org.junit.internal.runners.model.ReflectiveCallable",
+        "method": "run",
+        "file": "ReflectiveCallable.java",
+        "line": 12,
+        "exact": true,
+        "location": "junit-4.11.jar",
+        "version": "?"
+      }, {
+        "class": "org.junit.runners.model.FrameworkMethod",
+        "method": "invokeExplosively",
+        "file": "FrameworkMethod.java",
+        "line": 44,
+        "exact": true,
+        "location": "junit-4.11.jar",
+        "version": "?"
+      }, {
+        "class": "org.junit.internal.runners.statements.InvokeMethod",
+        "method": "evaluate",
+        "file": "InvokeMethod.java",
+        "line": 17,
+        "exact": true,
+        "location": "junit-4.11.jar",
+        "version": "?"
+      }, {
+        "class": "org.junit.runners.ParentRunner",
+        "method": "runLeaf",
+        "file": "ParentRunner.java",
+        "line": 271,
+        "exact": true,
+        "location": "junit-4.11.jar",
+        "version": "?"
+      }, {
+        "class": "org.junit.runners.BlockJUnit4ClassRunner",
+        "method": "runChild",
+        "file": "BlockJUnit4ClassRunner.java",
+        "line": 70,
+        "exact": true,
+        "location": "junit-4.11.jar",
+        "version": "?"
+      }, {
+        "class": "org.junit.runners.BlockJUnit4ClassRunner",
+        "method": "runChild",
+        "file": "BlockJUnit4ClassRunner.java",
+        "line": 50,
+        "exact": true,
+        "location": "junit-4.11.jar",
+        "version": "?"
+      }, {
+        "class": "org.junit.runners.ParentRunner$3",
+        "method": "run",
+        "file": "ParentRunner.java",
+        "line": 238,
+        "exact": true,
+        "location": "junit-4.11.jar",
+        "version": "?"
+      }, {
+        "class": "org.junit.runners.ParentRunner$1",
+        "method": "schedule",
+        "file": "ParentRunner.java",
+        "line": 63,
+        "exact": true,
+        "location": "junit-4.11.jar",
+        "version": "?"
+      }, {
+        "class": "org.junit.runners.ParentRunner",
+        "method": "runChildren",
+        "file": "ParentRunner.java",
+        "line": 236,
+        "exact": true,
+        "location": "junit-4.11.jar",
+        "version": "?"
+      }, {
+        "class": "org.junit.runners.ParentRunner",
+        "method": "access$000",
+        "file": "ParentRunner.java",
+        "line": 53,
+        "exact": true,
+        "location": "junit-4.11.jar",
+        "version": "?"
+      }, {
+        "class": "org.junit.runners.ParentRunner$2",
+        "method": "evaluate",
+        "file": "ParentRunner.java",
+        "line": 229,
+        "exact": true,
+        "location": "junit-4.11.jar",
+        "version": "?"
+      }, {
+        "class": "org.junit.internal.runners.statements.RunBefores",
+        "method": "evaluate",
+        "file": "RunBefores.java",
+        "line": 26,
+        "exact": true,
+        "location": "junit-4.11.jar",
+        "version": "?"
+      }, {
+        "class": "org.junit.internal.runners.statements.RunAfters",
+        "method": "evaluate",
+        "file": "RunAfters.java",
+        "line": 27,
+        "exact": true,
+        "location": "junit-4.11.jar",
+        "version": "?"
+      }, {
+        "class": "org.junit.runners.ParentRunner",
+        "method": "run",
+        "file": "ParentRunner.java",
+        "line": 309,
+        "exact": true,
+        "location": "junit-4.11.jar",
+        "version": "?"
+      }, {
+        "class": "org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference",
+        "method": "run",
+        "file": "JUnit4TestReference.java",
+        "line": 50,
+        "exact": true,
+        "location": ".cp/",
+        "version": "?"
+      }, {
+        "class": "org.eclipse.jdt.internal.junit.runner.TestExecution",
+        "method": "run",
+        "file": "TestExecution.java",
+        "line": 38,
+        "exact": true,
+        "location": ".cp/",
+        "version": "?"
+      }, {
+        "class": "org.eclipse.jdt.internal.junit.runner.RemoteTestRunner",
+        "method": "runTests",
+        "file": "RemoteTestRunner.java",
+        "line": 467,
+        "exact": true,
+        "location": ".cp/",
+        "version": "?"
+      }, {
+        "class": "org.eclipse.jdt.internal.junit.runner.RemoteTestRunner",
+        "method": "runTests",
+        "file": "RemoteTestRunner.java",
+        "line": 683,
+        "exact": true,
+        "location": ".cp/",
+        "version": "?"
+      }, {
+        "class": "org.eclipse.jdt.internal.junit.runner.RemoteTestRunner",
+        "method": "run",
+        "file": "RemoteTestRunner.java",
+        "line": 390,
+        "exact": true,
+        "location": ".cp/",
+        "version": "?"
+      }, {
+        "class": "org.eclipse.jdt.internal.junit.runner.RemoteTestRunner",
+        "method": "main",
+        "file": "RemoteTestRunner.java",
+        "line": 197,
+        "exact": true,
+        "location": ".cp/",
+        "version": "?"
+      }],
+      "localizedMessage": "I am suppressed exception 1",
+      "message": "I am suppressed exception 1",
+      "name": "java.lang.IndexOutOfBoundsException"
+    }, {
+      "commonElementCount": 0,
+      "extendedStackTrace": [{
+        "class": "org.apache.logging.log4j.core.layout.LogEventFixtures",
+        "method": "createLogEvent",
+        "file": "LogEventFixtures.java",
+        "line": 58,
+        "exact": true,
+        "location": "test-classes/",
+        "version": "?"
+      }, {
+        "class": "org.apache.logging.log4j.core.layout.JsonLayoutTest",
+        "method": "testAllFeatures",
+        "file": "JsonLayoutTest.java",
+        "line": 105,
+        "exact": true,
+        "location": "test-classes/",
+        "version": "?"
+      }, {
+        "class": "org.apache.logging.log4j.core.layout.JsonLayoutTest",
+        "method": "testLocationOnCompactOnMdcOn",
+        "file": "JsonLayoutTest.java",
+        "line": 268,
+        "exact": true,
+        "location": "test-classes/",
+        "version": "?"
+      }, {
+        "class": "sun.reflect.NativeMethodAccessorImpl",
+        "method": "invoke",
+        "line": -1,
+        "exact": false,
+        "location": "?",
+        "version": "1.7.0_55"
+      }, {
+        "class": "sun.reflect.NativeMethodAccessorImpl",
+        "method": "invoke",
+        "line": -1,
+        "exact": false,
+        "location": "?",
+        "version": "1.7.0_55"
+      }, {
+        "class": "sun.reflect.DelegatingMethodAccessorImpl",
+        "method": "invoke",
+        "line": -1,
+        "exact": false,
+        "location": "?",
+        "version": "1.7.0_55"
+      }, {
+        "class": "java.lang.reflect.Method",
+        "method": "invoke",
+        "line": -1,
+        "exact": false,
+        "location": "?",
+        "version": "1.7.0_55"
+      }, {
+        "class": "org.junit.runners.model.FrameworkMethod$1",
+        "method": "runReflectiveCall",
+        "file": "FrameworkMethod.java",
+        "line": 47,
+        "exact": true,
+        "location": "junit-4.11.jar",
+        "version": "?"
+      }, {
+        "class": "org.junit.internal.runners.model.ReflectiveCallable",
+        "method": "run",
+        "file": "ReflectiveCallable.java",
+        "line": 12,
+        "exact": true,
+        "location": "junit-4.11.jar",
+        "version": "?"
+      }, {
+        "class": "org.junit.runners.model.FrameworkMethod",
+        "method": "invokeExplosively",
+        "file": "FrameworkMethod.java",
+        "line": 44,
+        "exact": true,
+        "location": "junit-4.11.jar",
+        "version": "?"
+      }, {
+        "class": "org.junit.internal.runners.statements.InvokeMethod",
+        "method": "evaluate",
+        "file": "InvokeMethod.java",
+        "line": 17,
+        "exact": true,
+        "location": "junit-4.11.jar",
+        "version": "?"
+      }, {
+        "class": "org.junit.runners.ParentRunner",
+        "method": "runLeaf",
+        "file": "ParentRunner.java",
+        "line": 271,
+        "exact": true,
+        "location": "junit-4.11.jar",
+        "version": "?"
+      }, {
+        "class": "org.junit.runners.BlockJUnit4ClassRunner",
+        "method": "runChild",
+        "file": "BlockJUnit4ClassRunner.java",
+        "line": 70,
+        "exact": true,
+        "location": "junit-4.11.jar",
+        "version": "?"
+      }, {
+        "class": "org.junit.runners.BlockJUnit4ClassRunner",
+        "method": "runChild",
+        "file": "BlockJUnit4ClassRunner.java",
+        "line": 50,
+        "exact": true,
+        "location": "junit-4.11.jar",
+        "version": "?"
+      }, {
+        "class": "org.junit.runners.ParentRunner$3",
+        "method": "run",
+        "file": "ParentRunner.java",
+        "line": 238,
+        "exact": true,
+        "location": "junit-4.11.jar",
+        "version": "?"
+      }, {
+        "class": "org.junit.runners.ParentRunner$1",
+        "method": "schedule",
+        "file": "ParentRunner.java",
+        "line": 63,
+        "exact": true,
+        "location": "junit-4.11.jar",
+        "version": "?"
+      }, {
+        "class": "org.junit.runners.ParentRunner",
+        "method": "runChildren",
+        "file": "ParentRunner.java",
+        "line": 236,
+        "exact": true,
+        "location": "junit-4.11.jar",
+        "version": "?"
+      }, {
+        "class": "org.junit.runners.ParentRunner",
+        "method": "access$000",
+        "file": "ParentRunner.java",
+        "line": 53,
+        "exact": true,
+        "location": "junit-4.11.jar",
+        "version": "?"
+      }, {
+        "class": "org.junit.runners.ParentRunner$2",
+        "method": "evaluate",
+        "file": "ParentRunner.java",
+        "line": 229,
+        "exact": true,
+        "location": "junit-4.11.jar",
+        "version": "?"
+      }, {
+        "class": "org.junit.internal.runners.statements.RunBefores",
+        "method": "evaluate",
+        "file": "RunBefores.java",
+        "line": 26,
+        "exact": true,
+        "location": "junit-4.11.jar",
+        "version": "?"
+      }, {
+        "class": "org.junit.internal.runners.statements.RunAfters",
+        "method": "evaluate",
+        "file": "RunAfters.java",
+        "line": 27,
+        "exact": true,
+        "location": "junit-4.11.jar",
+        "version": "?"
+      }, {
+        "class": "org.junit.runners.ParentRunner",
+        "method": "run",
+        "file": "ParentRunner.java",
+        "line": 309,
+        "exact": true,
+        "location": "junit-4.11.jar",
+        "version": "?"
+      }, {
+        "class": "org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference",
+        "method": "run",
+        "file": "JUnit4TestReference.java",
+        "line": 50,
+        "exact": true,
+        "location": ".cp/",
+        "version": "?"
+      }, {
+        "class": "org.eclipse.jdt.internal.junit.runner.TestExecution",
+        "method": "run",
+        "file": "TestExecution.java",
+        "line": 38,
+        "exact": true,
+        "location": ".cp/",
+        "version": "?"
+      }, {
+        "class": "org.eclipse.jdt.internal.junit.runner.RemoteTestRunner",
+        "method": "runTests",
+        "file": "RemoteTestRunner.java",
+        "line": 467,
+        "exact": true,
+        "location": ".cp/",
+        "version": "?"
+      }, {
+        "class": "org.eclipse.jdt.internal.junit.runner.RemoteTestRunner",
+        "method": "runTests",
+        "file": "RemoteTestRunner.java",
+        "line": 683,
+        "exact": true,
+        "location": ".cp/",
+        "version": "?"
+      }, {
+        "class": "org.eclipse.jdt.internal.junit.runner.RemoteTestRunner",
+        "method": "run",
+        "file": "RemoteTestRunner.java",
+        "line": 390,
+        "exact": true,
+        "location": ".cp/",
+        "version": "?"
+      }, {
+        "class": "org.eclipse.jdt.internal.junit.runner.RemoteTestRunner",
+        "method": "main",
+        "file": "RemoteTestRunner.java",
+        "line": 197,
+        "exact": true,
+        "location": ".cp/",
+        "version": "?"
+      }],
+      "localizedMessage": "I am suppressed exception 2",
+      "message": "I am suppressed exception 2",
+      "name": "java.lang.IndexOutOfBoundsException"
+    }]
+  },
+  "loggerFQCN": "f.q.c.n",
+  "endOfBatch": false,
+  "contextMap": [{
+    "key": "MDC.B",
+    "value": "B_Value"
+  }, {
+    "key": "MDC.A",
+    "value": "A_Value"
+  }],
+  "contextStack": ["stack_msg1", "stack_msg2"],
+  "source": {
+    "class": "org.apache.logging.log4j.core.layout.LogEventFixtures",
+    "method": "createLogEvent",
+    "file": "LogEventFixtures.java",
+    "line": 54
+  }
+}
+ * </pre>
+ * <p>
+ * If {@code complete="false"}, the appender does not write the JSON open array character "[" at the start of the document. and "]" and the
+ * end.
+ * </p>
+ * <p>
+ * This approach enforces the independence of the JsonLayout and the appender where you embed it.
+ * </p>
+ * <h4>Encoding</h4>
+ * <p>
+ * Appenders using this layout should have their {@code charset} set to {@code UTF-8} or {@code UTF-16}, otherwise events containing non
+ * ASCII characters could result in corrupted log files.
+ * </p>
+ * <h4>Pretty vs. compact XML</h4>
+ * <p>
+ * By default, the JSON layout is not compact (a.k.a. not "pretty") with {@code compact="false"}, which means the appender uses end-of-line
+ * characters and indents lines to format the text. If {@code compact="true"}, then no end-of-line or indentation is used. Message content
+ * may contain, of course, escaped end-of-lines.
+ * </p>
+ */
+@Plugin(name = "JsonLayout", category = "Core", elementType = "layout", printObject = true)
+public final class JsonLayout extends AbstractJacksonLayout {
+
+    protected JsonLayout(final boolean locationInfo, final boolean properties, final boolean complete, final boolean compact,
+            final Charset charset) {
+        super(new JacksonFactory.JSON().newWriter(locationInfo, properties, compact), charset, compact, complete);
+    }
+
+    /**
+     * Returns appropriate JSON headers.
+     * 
+     * @return a byte array containing the header, opening the JSON array.
+     */
+    @Override
+    public byte[] getHeader() {
+        if (!this.complete) {
+            return null;
+        }
+        final StringBuilder buf = new StringBuilder();
+        buf.append('[');
+        buf.append(this.eol);
+        return buf.toString().getBytes(this.getCharset());
+    }
+
+    /**
+     * Returns appropriate JSON footer.
+     * 
+     * @return a byte array containing the footer, closing the JSON array.
+     */
+    @Override
+    public byte[] getFooter() {
+        if (!this.complete) {
+            return null;
+        }
+        return (this.eol + ']' + this.eol).getBytes(this.getCharset());
+    }
+
+    @Override
+    public Map<String, String> getContentFormat() {
+        final Map<String, String> result = new HashMap<String, String>();
+        result.put("version", "2.0");
+        return result;
+    }
+
+    @Override
+    /**
+     * @return The content type.
+     */
+    public String getContentType() {
+        return "application/json; charset=" + this.getCharset();
+    }
+
+    /**
+     * Creates an XML Layout.
+     * 
+     * @param locationInfo If "true", includes the location information in the generated JSON.
+     * @param properties If "true", includes the thread context in the generated JSON.
+     * @param completeStr If "true", includes the JSON header and footer, defaults to "false".
+     * @param compactStr If "true", does not use end-of-lines and indentation, defaults to "false".
+     * @param charsetName The character set to use, if {@code null}, uses "UTF-8".
+     * @return An XML Layout.
+     */
+    @PluginFactory
+    public static AbstractJacksonLayout createLayout(
+            // @formatter:off
+            @PluginAttribute("locationInfo") final String locationInfo,
+            @PluginAttribute("properties") final String properties,
+            @PluginAttribute("complete") final String completeStr, 
+            @PluginAttribute("compact") final String compactStr,
+            @PluginAttribute("charset") final String charsetName
+            // @formatter:on
+    ) {
+        final Charset charset = Charsets.getSupportedCharset(charsetName, Charsets.UTF_8);
+        final boolean info = Boolean.parseBoolean(locationInfo);
+        final boolean props = Boolean.parseBoolean(properties);
+        final boolean complete = Boolean.parseBoolean(completeStr);
+        final boolean compact = Boolean.parseBoolean(compactStr);
+        return new JsonLayout(info, props, complete, compact, charset);
+    }
+}

Propchange: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/JsonLayout.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/JsonLayout.java
------------------------------------------------------------------------------
    svn:keywords = Id