@RunWith(BlockJUnit4ClassRunner.class)
public abstract class BasicTest {

    protected final void checkUtilConstructorContract(final Class<?> utilClass) {
        PrivateConstructorChecker
            .forClass(utilClass)
            .expectedTypeOfException(UnsupportedOperationException.class)
            .check();
    }

} @SuppressWarnings("serial")
public class LoggerInstantiationException extends HeraldException {

    private final LogFactory loggerFactory;


    public LoggerInstantiationException(final LogFactory loggerFactory) {
        this.loggerFactory = loggerFactory;
    }


    /**
     * Get logger factory, see {@link LogFactory}.
     *
     * @return logger factory
     */
    public LogFactory getLoggerFactory() {
        return loggerFactory;
    }


    /**
     * {@inheritDoc}
     */
    @Override
    public String getMessage() {
        return String.format("Can't create logger using factory %s", getLoggerFactory());
    }

} public class NullLoggerBean {

    @Log
    private NullLogger logger;

    public NullLogger getLogger() {
        return logger;
    }

} @SuppressWarnings("all")
@JService(LogFactory.class)
public class CommonsLogFactory extends SimpleLogFactory {

    public static final String LOGGER_CLASS_NAME = "org.apache.commons.logging.Log";
    public static final String FACTORY_CLASS_NAME = "org.apache.commons.logging.LogFactory";
    public static final String FACTORY_METHOD_NAME = "getLog";


    public CommonsLogFactory() {
        super(LOGGER_CLASS_NAME, FACTORY_CLASS_NAME, FACTORY_METHOD_NAME);
    }
    
} @SuppressWarnings("all")
@JService(LogFactory.class)
public class FluentLogFactory extends SimpleLogFactory {

    public static final String LOGGER_CLASS_NAME = "org.fluentd.logger.FluentLogger";
    public static final String FACTORY_CLASS_NAME = LOGGER_CLASS_NAME;
    public static final String FACTORY_METHOD_NAME = "getLogger";


    public FluentLogFactory() {
        super(LOGGER_CLASS_NAME, FACTORY_CLASS_NAME, FACTORY_METHOD_NAME);
    }


    /**
     * {@inheritDoc}
     */
    @Override
    public Object createLogger(final Class<?> clazz) {
        return createLogger(clazz.getSimpleName());
    }
    
} @SuppressWarnings("all")
@JService(LogFactory.class)
public class JBossLogFactory extends SimpleLogFactory {

    public static final String LOGGER_CLASS_NAME = "org.jboss.logging.Logger";
    public static final String FACTORY_CLASS_NAME = LOGGER_CLASS_NAME;
    public static final String FACTORY_METHOD_NAME = "getLogger";


    public JBossLogFactory() {
        super(LOGGER_CLASS_NAME, FACTORY_CLASS_NAME, FACTORY_METHOD_NAME);
    }

} @SuppressWarnings("all")
@JService(LogFactory.class)
public class JavaUtilLogFactory extends SimpleLogFactory {

    public static final String LOGGER_CLASS_NAME = "java.util.logging.Logger";
    public static final String FACTORY_CLASS_NAME = LOGGER_CLASS_NAME;
    public static final String FACTORY_METHOD_NAME = "getLogger";

    
    public JavaUtilLogFactory() {
        super(LOGGER_CLASS_NAME, FACTORY_CLASS_NAME, FACTORY_METHOD_NAME);
    }


    /**
     * {@inheritDoc}
     */
    @Override
    public Object createLogger(final Class<?> clazz) {
        return createLogger(clazz.getSimpleName());
    }
    
} @SuppressWarnings("all")
@JService(LogFactory.class)
public class Log4j2LogFactory extends SimpleLogFactory {

    public static final String LOGGER_CLASS_NAME = "org.apache.logging.log4j.Logger";
    public static final String FACTORY_CLASS_NAME = "org.apache.logging.log4j.LogManager";
    public static final String FACTORY_METHOD_NAME = "getLogger";


    public Log4j2LogFactory() {
        super(LOGGER_CLASS_NAME, FACTORY_CLASS_NAME, FACTORY_METHOD_NAME);
    }

} @SuppressWarnings("all")
@JService(LogFactory.class)
public class Log4jLogFactory extends SimpleLogFactory {

    public static final String LOGGER_CLASS_NAME = "org.apache.log4j.Logger";
    public static final String FACTORY_CLASS_NAME = LOGGER_CLASS_NAME;
    public static final String FACTORY_METHOD_NAME = "getLogger";


    public Log4jLogFactory() {
        super(LOGGER_CLASS_NAME, FACTORY_CLASS_NAME, FACTORY_METHOD_NAME);
    }
    
} @SuppressWarnings("all")
@JService(LogFactory.class)
public class Slf4jExtLogFactory extends SimpleLogFactory {

    public static final String LOGGER_CLASS_NAME = "org.slf4j.ext.XLogger";
    public static final String FACTORY_CLASS_NAME = "org.slf4j.ext.XLoggerFactory";
    public static final String FACTORY_METHOD_NAME = "getXLogger";


    public Slf4jExtLogFactory() {
        super(LOGGER_CLASS_NAME, FACTORY_CLASS_NAME, FACTORY_METHOD_NAME);
    }

} @SuppressWarnings("all")
@JService(LogFactory.class)
public class Slf4jLogFactory extends SimpleLogFactory {

    public static final String LOGGER_CLASS_NAME = "org.slf4j.Logger";
    public static final String FACTORY_CLASS_NAME = "org.slf4j.LoggerFactory";
    public static final String FACTORY_METHOD_NAME = "getLogger";


    public Slf4jLogFactory() {
        super(LOGGER_CLASS_NAME, FACTORY_CLASS_NAME, FACTORY_METHOD_NAME);
    }
    
} @SuppressWarnings("all")
@JService(LogFactory.class)
public class Syslog4jGraylogLogFactory extends SimpleLogFactory {

    public static final String LOGGER_CLASS_NAME = "org.graylog2.syslog4j.SyslogIF";
    public static final String FACTORY_CLASS_NAME = "org.graylog2.syslog4j.Syslog";
    public static final String FACTORY_METHOD_NAME = "getInstance";

    public static final String DEFAULT_PROTOCOL = "udp";


    public Syslog4jGraylogLogFactory() {
        super(LOGGER_CLASS_NAME, FACTORY_CLASS_NAME, FACTORY_METHOD_NAME);
    }


    /**
     * Create SyslogIF client using {@value #DEFAULT_PROTOCOL}.
     *
     * @param clazz parameters is not used
     * @return logger
     */
    @Override
    public Object createLogger(final Class<?> clazz) {
        return createLogger(DEFAULT_PROTOCOL);
    }

} @JService(LogFactory.class)
public class Syslog4jLogFactory extends SimpleLogFactory {

    public static final String LOGGER_CLASS_NAME = "org.productivity.java.syslog4j.SyslogIF";
    public static final String FACTORY_CLASS_NAME = "org.productivity.java.syslog4j.Syslog";
    public static final String FACTORY_METHOD_NAME = "getInstance";

    public static final String DEFAULT_PROTOCOL = "udp";


    public Syslog4jLogFactory() {
        super(LOGGER_CLASS_NAME, FACTORY_CLASS_NAME, FACTORY_METHOD_NAME);
    }


    /**
     * Create SyslogIF client using {@value #DEFAULT_PROTOCOL}.
     *
     * @param clazz parameters is not used
     * @return logger
     */
    @Override
    public Object createLogger(final Class<?> clazz) {
        return createLogger(DEFAULT_PROTOCOL);
    }


} public final class LoggerInjector {

    private static final Collection<LogFactory> LOG_FACTORIES = loadLogFactories();


    private LoggerInjector() {
        throw new UnsupportedOperationException();
    }


    public static void inject(final Object... beans) {
        if (beans != null) {
            for (final Object bean : beans) {
                inject(bean);
            }
        }
    }

    public static <T> T inject(final T bean) {
        if (bean != null) {
            final Class<?> beanClass = bean.getClass();
            final Field[] declaredFields = beanClass.getDeclaredFields();

            for (final Field field : declaredFields) {
                if (needToInjectLogger(beanClass, field)) {
                    injectLogger(bean, field);
                }
            }
        }
        return bean;
    }


    /*
     * Internal API.
     */

    private static boolean needToInjectLogger(final Class<?> beanClass, final Field field) {
        final boolean hasAnnotation = beanClass.getAnnotation(Log.class) != null;
        if (hasAnnotation) {
            final Class<?> fieldType = field.getType();
            return LogFactoryDetector.hasCompatible(LOG_FACTORIES, fieldType);
        }
        return field.getAnnotation(Log.class) != null;
    }

    private static void injectLogger(final Object bean, final Field field) {
        final boolean isAccessible = field.isAccessible();
        ReflectionUtils.setAccessible(field, true);

        // Read context parameters.
        final Class<?> beanClass = bean.getClass();
        final Class<?> loggerClass = field.getType();
        final Log annotation = ReflectionUtils.findAnnotation(Log.class, beanClass, field);

        final boolean required = annotation.required();
        final String loggerName = annotation.value();

        try {
            final Object logger = createLogger(beanClass, loggerClass, loggerName);
            field.set(bean, logger);
        } catch (final Throwable ex) {
            if (required) {
                ReflectionUtils.handleReflectionException(ex);
            }
        } finally {
            ReflectionUtils.setAccessible(field, isAccessible);
        }
    }

    private static Object createLogger(
        final Class<?> beanClass, final Class<?> loggerClass, final String loggerName
    ) {
        // Find corresponding logger factory.
        final LogFactory logFactory =
            LogFactoryDetector.findCompatible(LOG_FACTORIES, loggerClass);

        if (logFactory == null) {
            throw new MissedLogFactoryException(loggerClass);
        }

        // Create logger.
        final Object logger = !loggerName.isEmpty()
            ? logFactory.createLogger(loggerName) : logFactory.createLogger(beanClass);

        if (logger == null) {
            throw new LoggerInstantiationException(logFactory);
        }
        return logger;
    }

    private static Collection<LogFactory> loadLogFactories() {
        return ServiceLoaderUtils.load(LogFactory.class);
    }

}
import com.github.vbauer.herald.core.BasicTest;
import com.github.vbauer.herald.exception.LoggerInstantiationException;
import com.github.vbauer.herald.ext.spring.bean.NullLoggerBean;
import com.github.vbauer.herald.logger.impl.CommonsLogFactory;
import com.github.vbauer.herald.logger.impl.FluentLogFactory;
import com.github.vbauer.herald.logger.impl.JBossLogFactory;
import com.github.vbauer.herald.logger.impl.JavaUtilLogFactory;
import com.github.vbauer.herald.logger.impl.Log4j2LogFactory;
import com.github.vbauer.herald.logger.impl.Log4jLogFactory;
import com.github.vbauer.herald.logger.impl.Slf4jExtLogFactory;
import com.github.vbauer.herald.logger.impl.Slf4jLogFactory;
import com.github.vbauer.herald.logger.impl.Syslog4jGraylogLogFactory;
import com.github.vbauer.herald.logger.impl.Syslog4jLogFactory;
import com.github.vbauer.herald.injector.LoggerInjector;
import org.junit.Test;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.notNullValue;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
package com.github.vbauer.herald.logger;



/**
 * @author Vladislav Bauer
 */

public class LogFactoryTest extends BasicTest {
    
    private static final String LOG_NAME = "Logger Name";


    @Test(expected = LoggerInstantiationException.class)
    public void testWrongCustomLogFactory() {
        final NullLoggerBean bean = new NullLoggerBean();
        fail(LoggerInjector.inject(bean).toString());
    }

    @Test
    public void testLogFactories() {
        checkLogFactory(new JavaUtilLogFactory(), LOG_NAME, java.util.logging.Logger.class);