logging-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ggreg...@apache.org
Subject svn commit: r1481026 [1/2] - in /logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db: ./ jdbc/ jpa/ nosql/ nosql/couch/ nosql/mongo/
Date Fri, 10 May 2013 14:32:04 GMT
Author: ggregory
Date: Fri May 10 14:32:03 2013
New Revision: 1481026

URL: http://svn.apache.org/r1481026
Log:
[LOG4J2-229] New JDBC, JPA, and NoSQL database Appenders. Oops, forgot to add new files.

Added:
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseAppender.java   (with props)
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseManager.java   (with props)
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/ColumnConfig.java   (with props)
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/ConnectionSource.java   (with props)
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/DataSourceConnectionSource.java   (with props)
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/DriverManagerConnectionSource.java   (with props)
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/FactoryMethodConnectionSource.java   (with props)
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/JDBCAppender.java   (with props)
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/JDBCDatabaseManager.java   (with props)
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/package-info.java   (with props)
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/JPAAppender.java   (with props)
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/JPADatabaseManager.java   (with props)
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/LogEventWrapperEntity.java   (with props)
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/package-info.java   (with props)
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/nosql/
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/nosql/NoSQLAppender.java   (with props)
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/nosql/NoSQLConnection.java   (with props)
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/nosql/NoSQLDatabaseManager.java   (with props)
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/nosql/NoSQLObject.java   (with props)
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/nosql/NoSQLProvider.java   (with props)
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/nosql/couch/
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/nosql/couch/CouchDBConnection.java   (with props)
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/nosql/couch/CouchDBObject.java   (with props)
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/nosql/couch/CouchDBProvider.java   (with props)
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/nosql/couch/package-info.java   (with props)
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/nosql/mongo/
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/nosql/mongo/MongoDBConnection.java   (with props)
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/nosql/mongo/MongoDBObject.java   (with props)
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/nosql/mongo/MongoDBProvider.java   (with props)
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/nosql/mongo/package-info.java   (with props)
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/nosql/package-info.java   (with props)
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/package-info.java   (with props)

Added: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseAppender.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseAppender.java?rev=1481026&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseAppender.java (added)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseAppender.java Fri May 10 14:32:03 2013
@@ -0,0 +1,137 @@
+/*
+ * 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;
+
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import org.apache.logging.log4j.core.Filter;
+import org.apache.logging.log4j.core.Layout;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.appender.AbstractAppender;
+import org.apache.logging.log4j.core.appender.AppenderRuntimeException;
+
+/**
+ * An abstract Appender for writing events to a database of some type, be it relational or NoSQL. All database appenders
+ * should inherit from this base appender. Three implementations are currently provided:
+ * {@link org.apache.logging.log4j.core.appender.db.jdbc JDBC}, {@link org.apache.logging.log4j.core.appender.db.jpa
+ * JPA}, and {@link org.apache.logging.log4j.core.appender.db.nosql NoSQL}.
+ * 
+ * @param <T>
+ *            Specifies which type of {@link AbstractDatabaseManager} this Appender requires.
+ */
+public abstract class AbstractDatabaseAppender<T extends AbstractDatabaseManager> extends AbstractAppender<LogEvent> {
+    private final ReadWriteLock lock = new ReentrantReadWriteLock();
+    private T manager;
+    private final Lock readLock = lock.readLock();
+    private final Lock writeLock = lock.writeLock();
+
+    /**
+     * Instantiates the base appender.
+     * 
+     * @param name
+     *            The appender name.
+     * @param filter
+     *            The filter, if any, to use.
+     * @param handleException
+     *            Whether logging exceptions should be reported to the application.
+     * @param manager
+     *            The matching {@link AbstractDatabaseManager} implementation.
+     */
+    protected AbstractDatabaseAppender(final String name, final Filter filter, final boolean handleException,
+            final T manager) {
+        super(name, filter, null, handleException);
+        this.manager = manager;
+    }
+
+    @Override
+    public final void append(final LogEvent event) {
+        this.readLock.lock();
+        try {
+            this.getManager().write(event);
+        } catch (final AppenderRuntimeException e) {
+            this.error(
+                    "Unable to write to database [" + this.getManager().getName() + "] for appender [" + this.getName()
+                            + "].", e);
+            throw e;
+        } finally {
+            this.readLock.unlock();
+        }
+    }
+
+    /**
+     * This always returns {@code null}, as database appenders do not use a single layout. The JPA and NoSQL appenders
+     * do not use a layout at all. The JDBC appender has a layout-per-column pattern.
+     * 
+     * @return {@code null}.
+     */
+    @Override
+    public final Layout<LogEvent> getLayout() {
+        return null;
+    }
+
+    /**
+     * Returns the underlying manager in use within this appender.
+     * 
+     * @return the manager.
+     */
+    public final T getManager() {
+        return this.manager;
+    }
+
+    /**
+     * Replaces the underlying manager in use within this appender. This can be useful for manually changing the way log
+     * events are written to the database without losing buffered or in-progress events. The existing manager is
+     * released only after the new manager has been installed. This method is thread-safe.
+     * 
+     * @param manager
+     *            The new manager to install.
+     */
+    protected final void replaceManager(final T manager) {
+        this.writeLock.lock();
+        try {
+            final T old = this.getManager();
+            if (!manager.isConnected()) {
+                manager.connect();
+            }
+            this.manager = manager;
+            old.release();
+        } finally {
+            this.writeLock.unlock();
+        }
+    }
+
+    @Override
+    public final void start() {
+        if (this.getManager() == null) {
+            LOGGER.error("No AbstractDatabaseManager set for the appender named [" + this.getName() + "].");
+        }
+        super.start();
+        if (this.getManager() != null) {
+            this.getManager().connect();
+        }
+    }
+
+    @Override
+    public final void stop() {
+        super.stop();
+        if (this.getManager() != null) {
+            this.getManager().release();
+        }
+    }
+}

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

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

Added: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseManager.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseManager.java?rev=1481026&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseManager.java (added)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseManager.java Fri May 10 14:32:03 2013
@@ -0,0 +1,194 @@
+/*
+ * 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;
+
+import java.util.ArrayList;
+
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.appender.AbstractManager;
+import org.apache.logging.log4j.core.appender.ManagerFactory;
+
+/**
+ * Manager that allows database appenders to have their configuration reloaded without losing events.
+ */
+public abstract class AbstractDatabaseManager extends AbstractManager {
+    /**
+     * Implementations should extend this class for passing data between the getManager method and the manager factory
+     * class.
+     */
+    protected abstract static class AbstractFactoryData {
+        public final int bufferSize;
+
+        /**
+         * Constructs the base factory data.
+         * 
+         * @param bufferSize
+         *            The size of the buffer.
+         */
+        protected AbstractFactoryData(final int bufferSize) {
+            this.bufferSize = bufferSize;
+        }
+    }
+
+    /**
+     * Implementations should define their own getManager method and call this method from that to create or get
+     * existing managers.
+     * 
+     * @param name
+     *            The manager name, which should include any configuration details that one might want to be able to
+     *            reconfigure at runtime, such as database name, username, (hashed) password, etc.
+     * @param data
+     *            The concrete instance of {@link AbstractFactoryData} appropriate for the given manager.
+     * @param factory
+     *            A factory instance for creating the appropriate manager.
+     * @param <M>
+     *            The concrete manager type.
+     * @param <T>
+     *            The concrete {@link AbstractFactoryData} type.
+     * @return a new or existing manager of the specified type and name.
+     */
+    protected static <M extends AbstractDatabaseManager, T extends AbstractFactoryData> M getManager(final String name,
+            final T data, final ManagerFactory<M, T> factory) {
+        return AbstractManager.getManager(name, factory, data);
+    }
+
+    private final ArrayList<LogEvent> buffer;
+
+    private final int bufferSize;
+
+    private boolean connected = false;
+
+    /**
+     * Instantiates the base manager.
+     * 
+     * @param name
+     *            The manager name, which should include any configuration details that one might want to be able to
+     *            reconfigure at runtime, such as database name, username, (hashed) password, etc.
+     * @param bufferSize
+     *            The size of the log event buffer.
+     */
+    protected AbstractDatabaseManager(final String name, final int bufferSize) {
+        super(name);
+        this.bufferSize = bufferSize;
+        this.buffer = new ArrayList<LogEvent>(bufferSize + 1);
+    }
+
+    /**
+     * This method is called within the appender when the appender is started. If it has not already been called, it
+     * calls {@link #connectInternal()} and catches any exceptions it might throw.
+     */
+    public final synchronized void connect() {
+        if (!this.isConnected()) {
+            try {
+                this.connectInternal();
+                this.connected = true;
+            } catch (final Exception e) {
+                LOGGER.error("Could not connect database logging manager.", e);
+            }
+        }
+    }
+
+    /**
+     * Implementations should implement this method to perform any proprietary connection operations. This method will
+     * never be called twice on the same instance. It is safe to throw any exceptions from this method.
+     */
+    protected abstract void connectInternal();
+
+    /**
+     * This method is called from the {@link #release()} method when the appender is stopped or the appender's manager
+     * is replaced. If it has not already been called, it calls {@link #disconnectInternal()} and catches any exceptions
+     * it might throw.
+     */
+    public final synchronized void disconnect() {
+        this.flush();
+        if (this.isConnected()) {
+            try {
+                this.disconnectInternal();
+            } catch (final Exception e) {
+                LOGGER.warn("Error while disconnecting database logging manager.", e);
+            } finally {
+                this.connected = false;
+            }
+        }
+    }
+
+    /**
+     * Implementations should implement this method to perform any proprietary disconnection / shutdown operations. This
+     * method will never be called twice on the same instance, and it will only be called <em>after</em>
+     * {@link #connectInternal()}. It is safe to throw any exceptions from this method.
+     */
+    protected abstract void disconnectInternal();
+
+    /**
+     * This method is called automatically when the buffer size reaches its maximum or at the beginning of a call to
+     * {@link #disconnect()}. It can also be called manually to flush events to the database.
+     */
+    public final synchronized void flush() {
+        if (this.isConnected() && this.buffer.size() > 0) {
+            for (final LogEvent event : this.buffer) {
+                this.writeInternal(event);
+            }
+            this.buffer.clear();
+        }
+    }
+
+    /**
+     * Indicates whether the manager is currently connected {@link #connect()} has been called and {@link #disconnect()}
+     * has not been called).
+     * 
+     * @return {@code true} if the manager is connected.
+     */
+    public final boolean isConnected() {
+        return this.connected;
+    }
+
+    @Override
+    public final void releaseSub() {
+        this.disconnect();
+    }
+
+    @Override
+    public final String toString() {
+        return this.getName();
+    }
+
+    /**
+     * This method manages buffering and writing of events.
+     * 
+     * @param event
+     *            The event to write to the database.
+     */
+    public final synchronized void write(final LogEvent event) {
+        if (this.bufferSize > 0) {
+            this.buffer.add(event);
+            if (this.buffer.size() >= this.bufferSize || event.isEndOfBatch()) {
+                this.flush();
+            }
+        } else {
+            this.writeInternal(event);
+        }
+    }
+
+    /**
+     * Performs the actual writing of the event in an implementation-specific way. This method is called immediately
+     * from {@link #write(LogEvent)} if buffering is off, or from {@link #flush()} if the buffer has reached its limit.
+     * 
+     * @param event
+     *            The event to write to the database.
+     */
+    protected abstract void writeInternal(LogEvent event);
+}

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

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

Added: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/ColumnConfig.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/ColumnConfig.java?rev=1481026&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/ColumnConfig.java (added)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/ColumnConfig.java Fri May 10 14:32:03 2013
@@ -0,0 +1,120 @@
+/*
+ * 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.Logger;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.config.plugins.PluginAttr;
+import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
+import org.apache.logging.log4j.core.config.plugins.PluginFactory;
+import org.apache.logging.log4j.core.layout.PatternLayout;
+import org.apache.logging.log4j.status.StatusLogger;
+
+/**
+ * A configuration element used to configure which event properties are logged to which columns in the database table.
+ */
+@Plugin(name = "Column", category = "Core", printObject = true)
+public final class ColumnConfig {
+    private static final Logger LOGGER = StatusLogger.getLogger();
+
+    /**
+     * Factory method for creating a column config within the plugin manager.
+     * 
+     * @param config
+     *            The configuration object
+     * @param name
+     *            The name of the database column as it exists within the database table.
+     * @param pattern
+     *            The {@link PatternLayout} pattern to insert in this column. Mutually exclusive with
+     *            {@code literalValue!=null} and {@code eventTimestamp=true}
+     * @param literalValue
+     *            The literal value to insert into the column as-is without any quoting or escaping. Mutually exclusive
+     *            with {@code pattern!=null} and {@code eventTimestamp=true}.
+     * @param eventTimestamp
+     *            If {@code "true"}, indicates that this column is a date-time column in which the event timestamp
+     *            should be inserted. Mutually exclusive with {@code pattern!=null} and {@code literalValue!=null}.
+     * @return the created column config.
+     */
+    @PluginFactory
+    public static ColumnConfig createColumnConfig(@PluginConfiguration final Configuration config,
+            @PluginAttr("name") final String name, @PluginAttr("pattern") final String pattern,
+            @PluginAttr("literal") final String literalValue,
+            @PluginAttr("isEventTimestamp") final String eventTimestamp) {
+        if (name == null || name.length() == 0) {
+            LOGGER.error("The column config is not valid because it does not contain a column name.");
+            return null;
+        }
+
+        final boolean isEventTimestamp = eventTimestamp != null && Boolean.parseBoolean(eventTimestamp);
+        final boolean isLiteralValue = literalValue != null && literalValue.length() > 0;
+        final boolean isPattern = pattern != null && pattern.length() > 0;
+
+        if ((isEventTimestamp && isLiteralValue) || (isEventTimestamp && isPattern) || (isLiteralValue && isPattern)) {
+            LOGGER.error("The pattern, literal, and isEventTimestamp attributes are mutually exclusive.");
+            return null;
+        }
+
+        if (isEventTimestamp) {
+            return new ColumnConfig(name, null, null, true);
+        }
+        if (isLiteralValue) {
+            return new ColumnConfig(name, null, literalValue, false);
+        }
+        if (isPattern) {
+            return new ColumnConfig(name, PatternLayout.createLayout(pattern, config, null, null, "true"), null, false);
+        }
+
+        LOGGER.error("To configure a column you must specify a pattern or literal or set isEventDate to true.");
+        return null;
+    }
+
+    private final String columnName;
+    private final boolean eventTimestamp;
+    private final PatternLayout layout;
+    private final String literalValue;
+
+    private ColumnConfig(final String columnName, final PatternLayout layout, final String literalValue,
+            final boolean eventDate) {
+        this.columnName = columnName;
+        this.layout = layout;
+        this.literalValue = literalValue;
+        this.eventTimestamp = eventDate;
+    }
+
+    public String getColumnName() {
+        return this.columnName;
+    }
+
+    public PatternLayout getLayout() {
+        return this.layout;
+    }
+
+    public String getLiteralValue() {
+        return this.literalValue;
+    }
+
+    public boolean isEventTimestamp() {
+        return this.eventTimestamp;
+    }
+
+    @Override
+    public String toString() {
+        return "{ name=" + this.columnName + ", layout=" + this.layout + ", literal=" + this.literalValue
+                + ", timestamp=" + this.eventTimestamp + " }";
+    }
+}

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

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

Added: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/ConnectionSource.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/ConnectionSource.java?rev=1481026&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/ConnectionSource.java (added)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/ConnectionSource.java Fri May 10 14:32:03 2013
@@ -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.appender.db.jdbc;
+
+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
+ * connection sources meet your needs, you can simply create your own connection source.
+ */
+public interface ConnectionSource {
+    /**
+     * This should return a new connection every time it is called.
+     * 
+     * @return the SQL connection object.
+     * @throws SQLException
+     *             if a database error occurs.
+     */
+    Connection getConnection() throws SQLException;
+
+    @Override
+    String toString();
+}

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

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

Added: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/DataSourceConnectionSource.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/DataSourceConnectionSource.java?rev=1481026&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/DataSourceConnectionSource.java (added)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/DataSourceConnectionSource.java Fri May 10 14:32:03 2013
@@ -0,0 +1,87 @@
+/*
+ * 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.sql.Connection;
+import java.sql.SQLException;
+
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import javax.sql.DataSource;
+
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.config.plugins.PluginAttr;
+import org.apache.logging.log4j.core.config.plugins.PluginFactory;
+import org.apache.logging.log4j.status.StatusLogger;
+
+/**
+ * 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 {
+    private static final Logger LOGGER = StatusLogger.getLogger();
+
+    /**
+     * Factory method for creating a connection source within the plugin manager.
+     * 
+     * @param jndiName
+     *            The full JNDI path where the data source is bound. Should start with java:/comp/env or
+     *            environment-equivalent.
+     * @return the created connection source.
+     */
+    @PluginFactory
+    public static DataSourceConnectionSource createConnectionSource(@PluginAttr("jndiName") final String jndiName) {
+        if (jndiName == null || jndiName.length() == 0) {
+            LOGGER.error("No JNDI name provided.");
+            return null;
+        }
+
+        try {
+            final InitialContext context = new InitialContext();
+            final DataSource dataSource = (DataSource) context.lookup(jndiName);
+            if (dataSource == null) {
+                LOGGER.error("No data source found with JNDI name [" + jndiName + "].");
+                return null;
+            }
+
+            return new DataSourceConnectionSource(jndiName, dataSource);
+        } catch (final NamingException e) {
+            LOGGER.error(e.getMessage(), e);
+            return null;
+        }
+    }
+
+    private final DataSource dataSource;
+
+    private final String description;
+
+    private DataSourceConnectionSource(final String dataSourceName, final DataSource dataSource) {
+        this.dataSource = dataSource;
+        this.description = "dataSource{ name=" + dataSourceName + ", value=" + dataSource + " }";
+    }
+
+    @Override
+    public Connection getConnection() throws SQLException {
+        return this.dataSource.getConnection();
+    }
+
+    @Override
+    public String toString() {
+        return this.description;
+    }
+}

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

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

Added: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/DriverManagerConnectionSource.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/DriverManagerConnectionSource.java?rev=1481026&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/DriverManagerConnectionSource.java (added)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/DriverManagerConnectionSource.java Fri May 10 14:32:03 2013
@@ -0,0 +1,107 @@
+/*
+ * 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.sql.Connection;
+import java.sql.Driver;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.config.plugins.PluginAttr;
+import org.apache.logging.log4j.core.config.plugins.PluginFactory;
+import org.apache.logging.log4j.core.helpers.NameUtil;
+import org.apache.logging.log4j.status.StatusLogger;
+
+/**
+ * A {@link JDBCAppender} connection source that uses a standard JDBC URL, username, and password to connect to the
+ * database.
+ */
+@Plugin(name = "DriverManager", category = "Core", elementType = "connectionSource", printObject = true)
+public final class DriverManagerConnectionSource implements ConnectionSource {
+    private static final Logger LOGGER = StatusLogger.getLogger();
+
+    /**
+     * Factory method for creating a connection source within the plugin manager.
+     * 
+     * @param url
+     *            The JDBC URL to use to connect to the logging database. A driver that can accept this URL must be on
+     *            the classpath.
+     * @param username
+     *            The username with which to log in to the database, if applicable.
+     * @param password
+     *            The password with which to log in to the database, if applicable.
+     * @return the created connection source.
+     */
+    @PluginFactory
+    public static DriverManagerConnectionSource createConnectionSource(@PluginAttr("url") final String url,
+            @PluginAttr("username") String username, @PluginAttr("password") String password) {
+        if (url == null || url.length() == 0) {
+            LOGGER.error("No JDBC URL specified for the database.", url);
+            return null;
+        }
+
+        Driver driver;
+        try {
+            driver = DriverManager.getDriver(url);
+        } catch (final SQLException e) {
+            LOGGER.error("No matching driver found for database URL [" + url + "].", e);
+            return null;
+        }
+
+        if (driver == null) {
+            LOGGER.error("No matching driver found for database URL [" + url + "].");
+            return null;
+        }
+
+        if (username == null || username.trim().length() == 0) {
+            username = null;
+            password = null;
+        }
+
+        return new DriverManagerConnectionSource(url, username, password);
+    }
+
+    private final String databasePassword;
+    private final String databaseUrl;
+    private final String databaseUsername;
+
+    private final String description;
+
+    private DriverManagerConnectionSource(final String databaseUrl, final String databaseUsername,
+            final String databasePassword) {
+        this.databaseUrl = databaseUrl;
+        this.databaseUsername = databaseUsername;
+        this.databasePassword = databasePassword;
+        this.description = "driverManager{ url=" + this.databaseUrl + ", username=" + this.databaseUsername
+                + ", passwordHash=" + NameUtil.md5(this.databasePassword + this.getClass().getName()) + " }";
+    }
+
+    @Override
+    public Connection getConnection() throws SQLException {
+        if (this.databaseUsername == null) {
+            return DriverManager.getConnection(this.databaseUrl);
+        }
+        return DriverManager.getConnection(this.databaseUrl, this.databaseUsername, this.databasePassword);
+    }
+
+    @Override
+    public String toString() {
+        return this.description;
+    }
+}

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

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

Added: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/FactoryMethodConnectionSource.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/FactoryMethodConnectionSource.java?rev=1481026&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/FactoryMethodConnectionSource.java (added)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/FactoryMethodConnectionSource.java Fri May 10 14:32:03 2013
@@ -0,0 +1,158 @@
+/*
+ * 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.PrintWriter;
+import java.lang.reflect.Method;
+import java.sql.Connection;
+import java.sql.SQLException;
+
+import javax.sql.DataSource;
+
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.config.plugins.PluginAttr;
+import org.apache.logging.log4j.core.config.plugins.PluginFactory;
+import org.apache.logging.log4j.status.StatusLogger;
+
+/**
+ * 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)
+public final class FactoryMethodConnectionSource implements ConnectionSource {
+    private static final Logger LOGGER = StatusLogger.getLogger();
+
+    /**
+     * Factory method for creating a connection source within the plugin manager.
+     * 
+     * @param className
+     *            The name of a public class that contains a static method capable of returning either a
+     *            {@link DataSource} or a {@link Connection}.
+     * @param methodName
+     *            The name of the public static method on the aforementioned class that returns the data source or
+     *            connection. If this method returns a {@link Connection}, it should return a new connection every call.
+     * @return the created connection source.
+     */
+    @PluginFactory
+    public static FactoryMethodConnectionSource createConnectionSource(@PluginAttr("class") final String className,
+            @PluginAttr("method") final String methodName) {
+        if (className == null || className.length() == 0 || methodName == null || methodName.length() == 0) {
+            LOGGER.error("No class name or method name specified for the connection factory method.");
+            return null;
+        }
+
+        final Method method;
+        try {
+            final Class<?> factoryClass = Class.forName(className);
+            method = factoryClass.getMethod(methodName);
+        } catch (final Exception e) {
+            LOGGER.error(e.toString(), e);
+            return null;
+        }
+
+        final Class<?> returnType = method.getReturnType();
+        String returnTypeString = returnType.getName();
+        DataSource dataSource;
+        if (returnType == DataSource.class) {
+            try {
+                dataSource = (DataSource) method.invoke(null);
+                returnTypeString += "[" + dataSource + "]";
+            } catch (final Exception e) {
+                LOGGER.error(e.toString(), e);
+                return null;
+            }
+        } else if (returnType == Connection.class) {
+            dataSource = new DataSource() {
+                @Override
+                public Connection getConnection() throws SQLException {
+                    try {
+                        return (Connection) method.invoke(null);
+                    } catch (final Exception e) {
+                        throw new SQLException("Failed to obtain connection from factory method.", e);
+                    }
+                }
+
+                @Override
+                public Connection getConnection(final String username, final String password) throws SQLException {
+                    throw new UnsupportedOperationException();
+                }
+
+                @Override
+                public int getLoginTimeout() throws SQLException {
+                    throw new UnsupportedOperationException();
+                }
+
+                @Override
+                public PrintWriter getLogWriter() throws SQLException {
+                    throw new UnsupportedOperationException();
+                }
+
+                // method must be present to compile on Java 7, @Override must be absent to compile on Java 6
+                @SuppressWarnings("unused")
+                public java.util.logging.Logger getParentLogger() {
+                    throw new UnsupportedOperationException();
+                }
+
+                @Override
+                public boolean isWrapperFor(final Class<?> iface) throws SQLException {
+                    return false;
+                }
+
+                @Override
+                public void setLoginTimeout(final int seconds) throws SQLException {
+                    throw new UnsupportedOperationException();
+                }
+
+                @Override
+                public void setLogWriter(final PrintWriter out) throws SQLException {
+                    throw new UnsupportedOperationException();
+                }
+
+                @Override
+                public <T> T unwrap(final Class<T> iface) throws SQLException {
+                    return null;
+                }
+            };
+        } else {
+            LOGGER.error("Method [{}.{}()] returns unsupported type [{}].", className, methodName, returnType.getName());
+            return null;
+        }
+
+        return new FactoryMethodConnectionSource(dataSource, className, methodName, returnTypeString);
+    }
+
+    private final DataSource dataSource;
+
+    private final String description;
+
+    private FactoryMethodConnectionSource(final DataSource dataSource, final String className, final String methodName,
+            final String returnType) {
+        this.dataSource = dataSource;
+        this.description = "factory{ public static " + returnType + " " + className + "." + methodName + "() }";
+    }
+
+    @Override
+    public Connection getConnection() throws SQLException {
+        return this.dataSource.getConnection();
+    }
+
+    @Override
+    public String toString() {
+        return this.description;
+    }
+}

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

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

Added: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/JDBCAppender.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/JDBCAppender.java?rev=1481026&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/JDBCAppender.java (added)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/JDBCAppender.java Fri May 10 14:32:03 2013
@@ -0,0 +1,109 @@
+/*
+ * 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.db.AbstractDatabaseAppender;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.config.plugins.PluginAttr;
+import org.apache.logging.log4j.core.config.plugins.PluginElement;
+import org.apache.logging.log4j.core.config.plugins.PluginFactory;
+
+/**
+ * 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> {
+    /**
+     * Factory method for creating a JDBC appender within the plugin manager.
+     * 
+     * @param name
+     *            The name of the appender.
+     * @param suppressExceptions
+     *            {@code "true"} (default) if logging exceptions should be hidden from the application, false otherwise.
+     * @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(@PluginAttr("name") final String name,
+            @PluginAttr("suppressExceptions") final String suppressExceptions,
+            @PluginElement("filter") final Filter filter,
+            @PluginElement("connectionSource") final ConnectionSource connectionSource,
+            @PluginAttr("bufferSize") final String bufferSize, @PluginAttr("tableName") final String tableName,
+            @PluginElement("columnConfigs") final ColumnConfig[] columnConfigs) {
+        int bufferSizeInt;
+        try {
+            bufferSizeInt = bufferSize == null || bufferSize.length() == 0 ? 0 : Integer.parseInt(bufferSize);
+        } catch (final NumberFormatException e) {
+            LOGGER.warn("Buffer size [" + bufferSize + "] not an integer, using no buffer.");
+            bufferSizeInt = 0;
+        }
+
+        final boolean handleExceptions = suppressExceptions == null || !Boolean.parseBoolean(suppressExceptions);
+
+        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, handleExceptions, manager);
+    }
+
+    private final String description;
+
+    private JDBCAppender(final String name, final Filter filter, final boolean handleException,
+            final JDBCDatabaseManager manager) {
+        super(name, filter, handleException, manager);
+        this.description = this.getName() + "{ manager=" + this.getManager() + " }";
+    }
+
+    @Override
+    public String toString() {
+        return this.description;
+    }
+}

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

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

Added: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/JDBCDatabaseManager.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/JDBCDatabaseManager.java?rev=1481026&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/JDBCDatabaseManager.java (added)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/JDBCDatabaseManager.java Fri May 10 14:32:03 2013
@@ -0,0 +1,185 @@
+/*
+ * 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.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.ManagerFactory;
+import org.apache.logging.log4j.core.appender.db.AbstractDatabaseManager;
+import org.apache.logging.log4j.core.layout.PatternLayout;
+
+/**
+ * An {@link AbstractDatabaseManager} implementation for relational databases accessed via JDBC.
+ */
+public final class JDBCDatabaseManager extends AbstractDatabaseManager {
+    private static final class Column {
+        private final boolean isEventTimestamp;
+        private final PatternLayout layout;
+
+        private Column(final PatternLayout layout, final boolean isEventDate) {
+            this.layout = layout;
+            this.isEventTimestamp = isEventDate;
+        }
+    }
+
+    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;
+        }
+    }
+
+    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()));
+                    valuePart.append('?');
+                }
+            }
+
+            final String sqlStatement = "INSERT INTO " + data.tableName + " (" + columnPart + ") VALUES (" + valuePart
+                    + ")";
+
+            return new JDBCDatabaseManager(name, data.bufferSize, data.connectionSource, sqlStatement, columns);
+        }
+    }
+
+    private static final JDBCDatabaseManagerFactory FACTORY = new JDBCDatabaseManagerFactory();
+
+    /**
+     * 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);
+    }
+
+    private final List<Column> columns;
+
+    private Connection connection;
+
+    private final ConnectionSource connectionSource;
+
+    private final String sqlStatement;
+
+    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 connectInternal() {
+        try {
+            this.connection = this.connectionSource.getConnection();
+            this.statement = this.connection.prepareStatement(this.sqlStatement);
+        } catch (final SQLException e) {
+            LOGGER.error("Failed to connect to relational database using JDBC connection source [{}] in manager [{}].",
+                    this.connectionSource, this.getName(), e);
+        }
+    }
+
+    @Override
+    protected void disconnectInternal() {
+        try {
+            if (this.statement != null && !this.statement.isClosed()) {
+                this.statement.close();
+            }
+        } catch (final SQLException e) {
+            LOGGER.warn("Error while closing prepared statement in database manager [{}].", this.getName(), e);
+        }
+
+        try {
+            if (this.connection != null && !this.connection.isClosed()) {
+                this.connection.close();
+            }
+        } catch (final SQLException e) {
+            LOGGER.warn("Error while disconnecting from relational database in manager [{}].", this.getName(), e);
+        }
+    }
+
+    @Override
+    protected void writeInternal(final LogEvent event) {
+        try {
+            if (!this.isConnected() || this.connection == null || this.connection.isClosed()) {
+                LOGGER.error("Cannot write logging event; manager [{}] not connected to the database.", this.getName());
+                return;
+            }
+
+            int i = 1;
+            for (final Column column : this.columns) {
+                if (column.isEventTimestamp) {
+                    this.statement.setTimestamp(i++, new Timestamp(event.getMillis()));
+                } else {
+                    this.statement.setString(i++, column.layout.toSerializable(event));
+                }
+            }
+
+            if (this.statement.executeUpdate() == 0) {
+                LOGGER.warn("No records inserted in database table for log event in manager [{}].", this.getName());
+            }
+        } catch (final SQLException e) {
+            LOGGER.error("Failed to insert record for log event in manager [{}].", this.getName(), e);
+        }
+    }
+}

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

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

Added: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/package-info.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/package-info.java?rev=1481026&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/package-info.java (added)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/package-info.java Fri May 10 14:32:03 2013
@@ -0,0 +1,22 @@
+/*
+ * 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 JDBC Appender supports writing log events to a relational database using standard JDBC connections. You will need
+ * a JDBC driver on your classpath for the database you wish to log to.
+ */
+package org.apache.logging.log4j.core.appender.db.jdbc;
+

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

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

Added: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/JPAAppender.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/JPAAppender.java?rev=1481026&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/JPAAppender.java (added)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/JPAAppender.java Fri May 10 14:32:03 2013
@@ -0,0 +1,132 @@
+/*
+ * 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.db.AbstractDatabaseAppender;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.config.plugins.PluginAttr;
+import org.apache.logging.log4j.core.config.plugins.PluginElement;
+import org.apache.logging.log4j.core.config.plugins.PluginFactory;
+
+/**
+ * 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 LogEventWrapperEntity} class
+ * decorated with JPA annotations.
+ * 
+ * @see LogEventWrapperEntity
+ */
+@Plugin(name = "Jpa", category = "Core", elementType = "appender", printObject = true)
+public final class JPAAppender extends AbstractDatabaseAppender<JPADatabaseManager> {
+    /**
+     * Factory method for creating a JPA appender within the plugin manager.
+     * 
+     * @param name
+     *            The name of the appender.
+     * @param suppressExceptions
+     *            {@code "true"} (default) if logging exceptions should be hidden from the application, false otherwise.
+     * @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 LogEventWrapperEntity} 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(@PluginAttr("name") final String name,
+            @PluginAttr("suppressExceptions") final String suppressExceptions,
+            @PluginElement("filter") final Filter filter, @PluginAttr("bufferSize") final String bufferSize,
+            @PluginAttr("entityClassName") final String entityClassName,
+            @PluginAttr("persistenceUnitName") final String persistenceUnitName) {
+        if (entityClassName == null || entityClassName.length() == 0 || persistenceUnitName == null
+                || persistenceUnitName.length() == 0) {
+            LOGGER.error("Attributes entityClassName and persistenceUnitName are required for JPA Appender.");
+            return null;
+        }
+
+        int bufferSizeInt;
+        try {
+            bufferSizeInt = bufferSize == null || bufferSize.length() == 0 ? 0 : Integer.parseInt(bufferSize);
+        } catch (final NumberFormatException e) {
+            LOGGER.warn("Buffer size [" + bufferSize + "] not an integer, using no buffer.");
+            bufferSizeInt = 0;
+        }
+
+        final boolean handleExceptions = suppressExceptions == null || !Boolean.parseBoolean(suppressExceptions);
+
+        try {
+            @SuppressWarnings("unchecked")
+            final Class<? extends LogEventWrapperEntity> entityClass = (Class<? extends LogEventWrapperEntity>) Class
+                    .forName(entityClassName);
+
+            if (!LogEventWrapperEntity.class.isAssignableFrom(entityClass)) {
+                LOGGER.error("Entity class [{}] does not extend LogEventWrapperEntity.", 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 LogEventWrapperEntity> 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, handleExceptions, 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;
+        }
+    }
+
+    private final String description;
+
+    private JPAAppender(final String name, final Filter filter, final boolean handleException,
+            final JPADatabaseManager manager) {
+        super(name, filter, handleException, manager);
+        this.description = this.getName() + "{ manager=" + this.getManager() + " }";
+    }
+
+    @Override
+    public String toString() {
+        return this.description;
+    }
+}

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

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

Added: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/JPADatabaseManager.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/JPADatabaseManager.java?rev=1481026&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/JPADatabaseManager.java (added)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/JPADatabaseManager.java Fri May 10 14:32:03 2013
@@ -0,0 +1,146 @@
+/*
+ * 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.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 class FactoryData extends AbstractDatabaseManager.AbstractFactoryData {
+        private final Class<? extends LogEventWrapperEntity> entityClass;
+        private final Constructor<? extends LogEventWrapperEntity> entityConstructor;
+        private final String persistenceUnitName;
+
+        protected FactoryData(final int bufferSize, final Class<? extends LogEventWrapperEntity> entityClass,
+                final Constructor<? extends LogEventWrapperEntity> entityConstructor, final String persistenceUnitName) {
+            super(bufferSize);
+
+            this.entityClass = entityClass;
+            this.entityConstructor = entityConstructor;
+            this.persistenceUnitName = persistenceUnitName;
+        }
+    }
+
+    private static final class JPADatabaseManagerFactory implements ManagerFactory<JPADatabaseManager, FactoryData> {
+        @Override
+        public JPADatabaseManager createManager(final String name, final FactoryData data) {
+            return new JPADatabaseManager(name, data.bufferSize, data.entityClass, data.entityConstructor,
+                    data.persistenceUnitName);
+        }
+    }
+
+    private static final JPADatabaseManagerFactory FACTORY = new JPADatabaseManagerFactory();
+
+    /**
+     * 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 LogEventWrapperEntity} 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 LogEventWrapperEntity> entityClass,
+            final Constructor<? extends LogEventWrapperEntity> entityConstructor, final String persistenceUnitName) {
+
+        return AbstractDatabaseManager.getManager(name, new FactoryData(bufferSize, entityClass, entityConstructor,
+                persistenceUnitName), FACTORY);
+    }
+
+    private final String entityClassName;
+    private final Constructor<? extends LogEventWrapperEntity> entityConstructor;
+    private EntityManager entityManager;
+
+    private EntityManagerFactory entityManagerFactory;
+
+    private final String persistenceUnitName;
+
+    private EntityTransaction transaction;
+
+    private JPADatabaseManager(final String name, final int bufferSize,
+            final Class<? extends LogEventWrapperEntity> entityClass,
+            final Constructor<? extends LogEventWrapperEntity> entityConstructor, final String persistenceUnitName) {
+        super(name, bufferSize);
+        this.entityClassName = entityClass.getName();
+        this.entityConstructor = entityConstructor;
+        this.persistenceUnitName = persistenceUnitName;
+    }
+
+    @Override
+    protected void connectInternal() {
+        this.entityManagerFactory = Persistence.createEntityManagerFactory(this.persistenceUnitName);
+        this.entityManager = this.entityManagerFactory.createEntityManager();
+        this.transaction = this.entityManager.getTransaction();
+    }
+
+    @Override
+    protected void disconnectInternal() {
+        this.transaction = null;
+
+        if (this.entityManager != null && this.entityManager.isOpen()) {
+            this.entityManager.close();
+        }
+
+        if (this.entityManagerFactory != null && this.entityManagerFactory.isOpen()) {
+            this.entityManagerFactory.close();
+        }
+    }
+
+    @Override
+    protected void writeInternal(final LogEvent event) {
+        if (!this.isConnected() || this.transaction == null || this.entityManager == null
+                || this.entityManagerFactory == null) {
+            LOGGER.error("Cannot write logging event; manager [{}] not connected to the database.", this.getName());
+            return;
+        }
+
+        LogEventWrapperEntity entity;
+        try {
+            entity = this.entityConstructor.newInstance(event);
+        } catch (final Exception e) {
+            LOGGER.error("Failed to instantiate entity class {}.", this.entityClassName, e);
+            return;
+        }
+
+        try {
+            this.transaction.begin();
+            this.entityManager.persist(entity);
+            this.transaction.commit();
+        } catch (final Exception e) {
+            LOGGER.error("Failed to persist log event entity.", e);
+            this.transaction.rollback();
+        }
+    }
+}

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

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

Added: 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=1481026&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/LogEventWrapperEntity.java (added)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/LogEventWrapperEntity.java Fri May 10 14:32:03 2013
@@ -0,0 +1,160 @@
+/*
+ * 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.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;
+
+/**
+ * Users of the JPA appender MUST implement 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.<br>
+ * <br>
+ * 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}<br>
+ * <br>
+ * 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 <em>or</em> (probably easier) mark those methods {@link Transient @Transient} and create
+ * similar methods that return the String form of these properties.<br>
+ * <br>
+ * 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.
+ */
+@MappedSuperclass
+public abstract class LogEventWrapperEntity implements LogEvent {
+    /**
+     * Generated serial version ID.
+     */
+    private static final long serialVersionUID = 1L;
+    private final LogEvent wrappedEvent;
+
+    /**
+     * 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.
+     * 
+     * @param wrappedEvent
+     *            The underlying event from which information is obtained.
+     */
+    protected LogEventWrapperEntity(final LogEvent wrappedEvent) {
+        this.wrappedEvent = wrappedEvent;
+    }
+
+    /**
+     * All eventual accessor methods must call this method and delegate the method call to the underlying wrapped event.
+     * 
+     * @return The underlying event from which information is obtained.
+     */
+    @Transient
+    protected final LogEvent getWrappedEvent() {
+        return this.wrappedEvent;
+    }
+
+    @Override
+    @Transient
+    public final boolean isEndOfBatch() {
+        return this.getWrappedEvent().isEndOfBatch();
+    }
+
+    @Override
+    @Transient
+    public final boolean isIncludeLocation() {
+        return this.getWrappedEvent().isIncludeLocation();
+    }
+
+    @SuppressWarnings("unused")
+    public void setContextMap(final Map<String, String> contextMap) {
+        // this entity is write-only
+    }
+
+    @SuppressWarnings("unused")
+    public void setContextStack(final ThreadContext.ContextStack contextStack) {
+        // this entity is write-only
+    }
+
+    @Override
+    @Transient
+    public final void setEndOfBatch(final boolean endOfBatch) {
+        this.getWrappedEvent().setEndOfBatch(endOfBatch);
+    }
+
+    @SuppressWarnings("unused")
+    public void setFQCN(final String fqcn) {
+        // this entity is write-only
+    }
+
+    @Override
+    @Transient
+    public final void setIncludeLocation(final boolean locationRequired) {
+        this.getWrappedEvent().setIncludeLocation(locationRequired);
+    }
+
+    @SuppressWarnings("unused")
+    public void setLevel(final Level level) {
+        // this entity is write-only
+    }
+
+    @SuppressWarnings("unused")
+    public void setLoggerName(final String name) {
+        // this entity is write-only
+    }
+
+    @SuppressWarnings("unused")
+    public void setMarker(final Marker marker) {
+        // this entity is write-only
+    }
+
+    @SuppressWarnings("unused")
+    public void setMessage(final Message message) {
+        // this entity is write-only
+    }
+
+    @SuppressWarnings("unused")
+    public void setMillis(final long millis) {
+        // this entity is write-only
+    }
+
+    @SuppressWarnings("unused")
+    public void setSource(final StackTraceElement element) {
+        // this entity is write-only
+    }
+
+    @SuppressWarnings("unused")
+    public void setThreadName(final String name) {
+        // this entity is write-only
+    }
+
+    @SuppressWarnings("unused")
+    public void setThrown(final Throwable throwable) {
+        // this entity is write-only
+    }
+}

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

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

Added: 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=1481026&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/package-info.java (added)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/package-info.java Fri May 10 14:32:03 2013
@@ -0,0 +1,24 @@
+/*
+ * 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 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
+ * 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;
+

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

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



Mime
View raw message