All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.tracee.contextlogger.ConnectorFactory Maven / Gradle / Ivy

package io.tracee.contextlogger;

import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.tracee.contextlogger.connector.Connector;
import io.tracee.contextlogger.connector.ConnectorOutputProvider;
import io.tracee.contextlogger.connector.LogConnector;
import io.tracee.contextlogger.connector.WellKnownConnectorClassNames;

/**
 * Class to pipe messages to all configured connectors.
 * Created by Tobias Gindler, holisticon AG on 26.03.14.
 */
class ConnectorFactory {

    // Connector settings
    private static final Pattern KEY_MATCHER_PATTERN = Pattern.compile(TraceeContextLoggerConstants.SYSTEM_PROPERTY_CONTEXT_LOGGER_CONNECTOR_KEY_PATTERN);
    private static final String CONNECTOR_PROPERTY_GRABBER_PATTERN = TraceeContextLoggerConstants.SYSTEM_PROPERTY_CONNECTOR_PREFIX.replaceAll("\\.", "\\.")
            + "%s\\.(.*)";
    private static final Logger LOGGER = LoggerFactory.getLogger(TraceeContextLogger.class);
    private static final Map WELL_KNOW_CONNECTOR_MAPPINGS = new HashMap();

    static {
        WELL_KNOW_CONNECTOR_MAPPINGS.put("HttpConnector", WellKnownConnectorClassNames.HTTP_CONNECTOR);
        WELL_KNOW_CONNECTOR_MAPPINGS.put(LogConnector.class.getName(), LogConnector.class.getCanonicalName());
    }

    // Connector
    private final Map connectorMap = new HashMap();

    ConnectorFactory() {
        initConnectors();
    }

    /**
     * Initializes all available connectors.
     */
    private void initConnectors() {

        // first get all connector configuration Names
        Set connectorConfigurationNames = this.getConnectorConfigurationNames();

        for (String connectorConfigurationName : connectorConfigurationNames) {

            Connector connector = this.createConnector(connectorConfigurationName);

            if (connector != null) {

                this.connectorMap.put(connectorConfigurationName, connector);

            }

        }

        // Add mandatory logger
        if (!isConnectorConfigured(LogConnector.class)) {
            Connector logConnector = new LogConnector();
            this.connectorMap.put("LOGGER", logConnector);
        }

    }

    /**
     * Send error report to all initialized connector instances.
     *
     * @param connectorOutputProvider the context data provider used for output
     */
    final void sendErrorReportToConnectors(ConnectorOutputProvider connectorOutputProvider) {

        for (Connector connector : this.connectorMap.values()) {

            connector.sendErrorReport(connectorOutputProvider);

        }
    }

    /**
     * Extracts all names for connector configurations from System properties.
     *
     * @return a Set containing all connector configuration names
     */
    final Set getConnectorConfigurationNames() {

        Set connectorNames = new HashSet();

        Enumeration keyEnumeration = getSystemProperties().keys();
        while (keyEnumeration.hasMoreElements()) {
            String key = keyEnumeration.nextElement().toString();

            // check if property key has tracee connector format
            Matcher matcher = KEY_MATCHER_PATTERN.matcher(key);
            if (matcher.matches() && matcher.groupCount() > 0) {

                connectorNames.add(matcher.group(1));

            }

        }

        return connectorNames;

    }

    /**
     * Collects all properties for a given connector configuration name and writes them to a Map.
     *
     * @param connectorName the name of the connector configuration
     * @return a Map containing all properties for a connector configuration name
     */
    final Map getPropertiesForConnectorConfigurationName(final String connectorName) {

        final Map propertyMap = new HashMap();

        final String patternString = String.format(CONNECTOR_PROPERTY_GRABBER_PATTERN, connectorName);
        final Pattern propertyGrabPattern = Pattern.compile(patternString);

        final Set> entries = getSystemProperties().entrySet();

        for (Map.Entry entry : entries) {
            final String key = entry.getKey().toString();
            final Object value = entry.getValue();

            // check if property key has tracee connector format
            final Matcher matcher = propertyGrabPattern.matcher(key);
            if (value != null && matcher.matches() && matcher.groupCount() > 0) {

                final String propertyName = matcher.group(1);

                propertyMap.put(propertyName, value.toString());

            }

        }

        return propertyMap;

    }

    /**
     * Tries to create a Connector for a given connector configuration name.
     *
     * @param connectorConfigurationName the name of the connector configuration
     * @return the connector if it could be created and initialized without error, otherwise null
     */
    final Connector createConnector(final String connectorConfigurationName) {

        Map propertyMap = this.getPropertiesForConnectorConfigurationName(connectorConfigurationName);
        String type = propertyMap.get(TraceeContextLoggerConstants.SYSTEM_PROPERTY_CONTEXT_LOGGER_CONNECTOR_TYPE);

        // get canonical class name for well known connectors
        if (WELL_KNOW_CONNECTOR_MAPPINGS.containsKey(type)) {
            type = WELL_KNOW_CONNECTOR_MAPPINGS.get(type);
        }

        try {

            // try to create connector instance
            Connector connector = (Connector)Class.forName(type).newInstance();

            // now try to call init method
            connector.init(propertyMap);

            return connector;

        }
        catch (Exception e) {
            LOGGER.error("An error occurred while creating connector with name '" + connectorConfigurationName + "' of type '" + type + "'", e);
        }

        return null;
    }

    /**
     * Checks whether the LogConnector is defined or not.
     *
     * @param connectorClass the connector to check for
     * @return true, if LogConnector is already defined, otherwise false.
     */
    private boolean isConnectorConfigured(Class connectorClass) {
        for (Connector connector : this.connectorMap.values()) {

            if (connectorClass.isInstance(connector)) {
                return true;
            }

        }

        return false;
    }

    protected Properties getSystemProperties() {
        return System.getProperties();
    }

}