| /* |
| * 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.jdbc.appender; |
| |
| 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.Core; |
| import org.apache.logging.log4j.core.config.plugins.Plugin; |
| import org.apache.logging.log4j.core.config.plugins.PluginAttribute; |
| import org.apache.logging.log4j.core.config.plugins.PluginFactory; |
| import org.apache.logging.log4j.status.StatusLogger; |
| import org.apache.logging.log4j.util.LoaderUtil; |
| import org.apache.logging.log4j.util.Strings; |
| |
| /** |
| * A {@link JdbcAppender} connection source that uses a public static factory method to obtain a {@link Connection} or |
| * {@link DataSource}. |
| */ |
| @Plugin(name = "ConnectionFactory", category = Core.CATEGORY_NAME, elementType = "connectionSource", printObject = true) |
| public final class FactoryMethodConnectionSource extends AbstractConnectionSource { |
| private static final Logger LOGGER = StatusLogger.getLogger(); |
| |
| 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; |
| } |
| |
| /** |
| * 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( |
| @PluginAttribute("class") final String className, |
| @PluginAttribute("method") final String methodName) { |
| if (Strings.isEmpty(className) || Strings.isEmpty(methodName)) { |
| LOGGER.error("No class name or method name specified for the connection factory method."); |
| return null; |
| } |
| |
| final Method method; |
| try { |
| final Class<?> factoryClass = LoaderUtil.loadClass(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(); |
| } |
| |
| @Override |
| @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); |
| } |
| } |