View Javadoc

    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements. See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache license, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License. You may obtain a copy of the License at
    8    *
    9    *      http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the license for the specific language governing permissions and
    15   * limitations under the license.
    16   */
    17  package org.apache.logging.log4j.core.appender.db.jdbc;
    18
    19  import java.io.PrintWriter;
    20  import java.lang.reflect.Method;
    21  import java.sql.Connection;
    22  import java.sql.SQLException;
    23
    24  import javax.sql.DataSource;
    25
    26  import org.apache.logging.log4j.Logger;
    27  import org.apache.logging.log4j.core.config.plugins.Plugin;
    28  import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
    29  import org.apache.logging.log4j.core.config.plugins.PluginFactory;
    30  import org.apache.logging.log4j.core.util.Loader;
    31  import org.apache.logging.log4j.status.StatusLogger;
    32  import org.apache.logging.log4j.util.Strings;
    33
    34  /**
    35   * A {@link JdbcAppender} connection source that uses a public static factory method to obtain a {@link Connection} or
    36   * {@link DataSource}.
    37   */
    38  @Plugin(name = "ConnectionFactory", category = "Core", elementType = "connectionSource", printObject = true)
    39  public final class FactoryMethodConnectionSource implements ConnectionSource {
    40      private static final Logger LOGGER = StatusLogger.getLogger();
    41
    42      private final DataSource dataSource;
    43      private final String description;
    44
    45      private FactoryMethodConnectionSource(final DataSource dataSource, final String className, final String methodName,
    46                                            final String returnType) {
    47          this.dataSource = dataSource;
    48          this.description = "factory{ public static " + returnType + ' ' + className + '.' + methodName + "() }";
    49      }
    50
    51      @Override
    52      public Connection getConnection() throws SQLException {
    53          return this.dataSource.getConnection();
    54      }
    55
    56      @Override
    57      public String toString() {
    58          return this.description;
    59      }
    60
    61      /**
    62       * Factory method for creating a connection source within the plugin manager.
    63       *
    64       * @param className The name of a public class that contains a static method capable of returning either a
    65       *                  {@link DataSource} or a {@link Connection}.
    66       * @param methodName The name of the public static method on the aforementioned class that returns the data source
    67       *                   or connection. If this method returns a {@link Connection}, it should return a new connection
    68       *                   every call.
    69       * @return the created connection source.
    70       */
    71      @PluginFactory
    72      public static FactoryMethodConnectionSource createConnectionSource(
    73              @PluginAttribute("class") final String className,
    74              @PluginAttribute("method") final String methodName) {
    75          if (Strings.isEmpty(className) || Strings.isEmpty(methodName)) {
    76              LOGGER.error("No class name or method name specified for the connection factory method.");
    77              return null;
    78          }
    79
    80          final Method method;
    81          try {
    82              final Class<?> factoryClass = Loader.loadClass(className);
    83              method = factoryClass.getMethod(methodName);
    84          } catch (final Exception e) {
    85              LOGGER.error(e.toString(), e);
    86              return null;
    87          }
    88
    89          final Class<?> returnType = method.getReturnType();
    90          String returnTypeString = returnType.getName();
    91          DataSource dataSource;
    92          if (returnType == DataSource.class) {
    93              try {
    94                  dataSource = (DataSource) method.invoke(null);
    95                  returnTypeString += "[" + dataSource + ']';
    96              } catch (final Exception e) {
    97                  LOGGER.error(e.toString(), e);
    98                  return null;
    99              }
    100         } else if (returnType == Connection.class) {
    101             dataSource = new DataSource() {
    102                 @Override
    103                 public Connection getConnection() throws SQLException {
    104                     try {
    105                         return (Connection) method.invoke(null);
    106                     } catch (final Exception e) {
    107                         throw new SQLException("Failed to obtain connection from factory method.", e);
    108                     }
    109                 }
    110
    111                 @Override
    112                 public Connection getConnection(final String username, final String password) throws SQLException {
    113                     throw new UnsupportedOperationException();
    114                 }
    115
    116                 @Override
    117                 public int getLoginTimeout() throws SQLException {
    118                     throw new UnsupportedOperationException();
    119                 }
    120
    121                 @Override
    122                 public PrintWriter getLogWriter() throws SQLException {
    123                     throw new UnsupportedOperationException();
    124                 }
    125
    126                 // method must be present to compile on Java 7!
    127                 // @Override must be absent to compile on Java 6!
    128                 @SuppressWarnings("unused")
    129                 public java.util.logging.Logger getParentLogger() {
    130                     throw new UnsupportedOperationException();
    131                 }
    132
    133                 @Override
    134                 public boolean isWrapperFor(final Class<?> iface) throws SQLException {
    135                     return false;
    136                 }
    137
    138                 @Override
    139                 public void setLoginTimeout(final int seconds) throws SQLException {
    140                     throw new UnsupportedOperationException();
    141                 }
    142
    143                 @Override
    144                 public void setLogWriter(final PrintWriter out) throws SQLException {
    145                     throw new UnsupportedOperationException();
    146                 }
    147
    148                 @Override
    149                 public <T> T unwrap(final Class<T> iface) throws SQLException {
    150                     return null;
    151                 }
    152             };
    153         } else {
    154             LOGGER.error("Method [{}.{}()] returns unsupported type [{}].", className, methodName,
    155                     returnType.getName());
    156             return null;
    157         }
    158
    159         return new FactoryMethodConnectionSource(dataSource, className, methodName, returnTypeString);
    160     }
    161 }