org.apache.sqoop.core.SqoopConfiguration.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.sqoop.core.SqoopConfiguration.java

Source

/*
 * Copyright (C) 2016 Stratio (http://stratio.com)
 *
 * Licensed 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.sqoop.core;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.apache.sqoop.classification.InterfaceAudience;
import org.apache.sqoop.classification.InterfaceStability;
import org.apache.sqoop.common.MapContext;
import org.apache.sqoop.common.SqoopException;
import org.apache.sqoop.error.code.CoreError;
import org.apache.sqoop.utils.ClassUtils;

import static org.apache.sqoop.utils.ContextUtils.getUniqueStrings;

/**
 * Configuration manager that loads Sqoop configuration.
 */
@InterfaceAudience.Public
@InterfaceStability.Unstable
@edu.umd.cs.findbugs.annotations.SuppressWarnings("IS2_INCONSISTENT_SYNC")
public class SqoopConfiguration implements Reconfigurable {

    /**
     * Logger object.
     */
    public static final Logger LOG = Logger.getLogger(SqoopConfiguration.class);

    /**
     * Private instance to singleton of this class.
     */
    private static SqoopConfiguration instance;

    /**
     * Create default object by default.
     *
     * Every Sqoop server application needs one so this should not be performance issue.
     */
    static {
        instance = new SqoopConfiguration();
    }

    /**
     * The private constructor for the singleton class.
     */
    private SqoopConfiguration() {
    }

    /**
     * Return current instance.
     *
     * @return Current instance
     */
    public static SqoopConfiguration getInstance() {
        return instance;
    }

    /**
     * Allows to set instance in case that it's need.
     *
     * This method should not be normally used as the default instance should be sufficient. One target
     * user use case for this method are unit tests.
     *
     * @param newInstance New instance
     */
    public static void setInstance(SqoopConfiguration newInstance) {
        instance = newInstance;
    }

    private File configDir = null;
    private boolean initialized = false;
    private ConfigurationProvider provider = null;
    private Map<String, String> config = null;
    private Map<String, String> oldConfig = null;

    public synchronized void initialize() {
        if (initialized) {
            LOG.warn("Attempt to reinitialize the system, ignoring");
            return;
        }

        String configDirPath = System.getProperty(ConfigurationConstants.SYSPROP_CONFIG_DIR);
        if (configDirPath == null || configDirPath.trim().length() == 0) {
            throw new SqoopException(CoreError.CORE_0001,
                    "Environment variable " + ConfigurationConstants.SYSPROP_CONFIG_DIR + " is not set.");
        }

        configDir = new File(configDirPath);
        if (!configDir.exists() || !configDir.isDirectory()) {
            throw new SqoopException(CoreError.CORE_0001, configDirPath);
        }

        String bootstrapConfigFilePath = null;
        try {
            String configDirCanonicalPath = configDir.getCanonicalPath();
            bootstrapConfigFilePath = configDirCanonicalPath + "/" + ConfigurationConstants.FILENAME_BOOTCFG_FILE;

        } catch (IOException ex) {
            throw new SqoopException(CoreError.CORE_0001, configDirPath, ex);
        }

        File bootstrapConfig = new File(bootstrapConfigFilePath);
        if (!bootstrapConfig.exists() || !bootstrapConfig.isFile() || !bootstrapConfig.canRead()) {
            throw new SqoopException(CoreError.CORE_0002, bootstrapConfigFilePath);
        }

        Properties bootstrapProperties = new Properties();
        try (InputStream bootstrapPropStream = new FileInputStream(bootstrapConfig)) {
            bootstrapProperties.load(bootstrapPropStream);
        } catch (IOException ex) {
            throw new SqoopException(CoreError.CORE_0002, bootstrapConfigFilePath, ex);
        }

        String configProviderClassName = bootstrapProperties
                .getProperty(ConfigurationConstants.BOOTCFG_CONFIG_PROVIDER);

        if (configProviderClassName == null || configProviderClassName.trim().length() == 0) {
            throw new SqoopException(CoreError.CORE_0003, ConfigurationConstants.BOOTCFG_CONFIG_PROVIDER);
        }

        Class<?> configProviderClass = null;
        try {
            configProviderClass = Class.forName(configProviderClassName);
        } catch (ClassNotFoundException cnfe) {
            LOG.warn("Exception while trying to load configuration provider", cnfe);
        }

        if (configProviderClass == null) {
            ClassLoader ctxLoader = Thread.currentThread().getContextClassLoader();
            if (ctxLoader != null) {
                try {
                    configProviderClass = ctxLoader.loadClass(configProviderClassName);
                } catch (ClassNotFoundException cnfe) {
                    LOG.warn("Exception while trying to load configuration provider: " + configProviderClassName,
                            cnfe);
                }
            }
        }

        if (configProviderClass == null) {
            throw new SqoopException(CoreError.CORE_0004, configProviderClassName);
        }

        try {
            provider = (ConfigurationProvider) configProviderClass.newInstance();
        } catch (Exception ex) {
            throw new SqoopException(CoreError.CORE_0005, configProviderClassName, ex);
        }

        // Initialize the configuration provider
        provider.initialize(configDir, bootstrapProperties);
        configurationChanged();

        provider.registerListener(new CoreConfigurationListener(SqoopConfiguration.getInstance()));

        initialized = true;

        configureClassLoader();
    }

    public synchronized MapContext getContext() {
        if (!initialized) {
            throw new SqoopException(CoreError.CORE_0007);
        }

        return new MapContext(config);
    }

    public synchronized MapContext getOldContext() {
        if (!initialized) {
            throw new SqoopException(CoreError.CORE_0007);
        }

        if (oldConfig == null) {
            throw new SqoopException(CoreError.CORE_0008);
        }

        return new MapContext(oldConfig);
    }

    public synchronized void destroy() {
        if (provider != null) {
            try {
                provider.destroy();
            } catch (Exception ex) {
                LOG.error("Failed to shutdown configuration provider", ex);
            }
        }
        provider = null;
        configDir = null;
        config = null;
        oldConfig = null;
        initialized = false;
    }

    /**
     * Load extra classpath from sqoop configuration.
     */
    private synchronized void configureClassLoader() {
        LOG.info("Adding jars to current classloader from property: " + ConfigurationConstants.CLASSPATH);
        List<URL> urls = getJarsForProperty(ConfigurationConstants.CLASSPATH);

        // Chain the current thread classloader so that
        // configured classpath adds to existing classloader.
        // Existing classpath is not changed.
        ClassLoader currentThreadClassLoader = Thread.currentThread().getContextClassLoader();
        if (currentThreadClassLoader == null) {
            throw new SqoopException(CoreError.CORE_0009, "No thread context classloader to override.");
        }
        URLClassLoader classLoader = new URLClassLoader(urls.toArray(new URL[urls.size()]),
                currentThreadClassLoader);
        Thread.currentThread().setContextClassLoader(classLoader);
    }

    /**
     * Get the list of jars for a given property
     *
     * @param classpathProperty The property corresponding to the list of jars
     * @return A list of URLs pointing to the jars
     */
    public synchronized List<URL> getJarsForProperty(String classpathProperty) {
        List<URL> urls = new LinkedList<>();

        // CSV URL list separated by ":".
        String paths = getContext().getString(classpathProperty);

        if (StringUtils.isEmpty(paths)) {
            LOG.debug("Property " + classpathProperty + " is null or empty.");
        } else {
            Set<String> pathSet = getUniqueStrings(paths);
            for (String path : pathSet) {
                try {
                    LOG.debug("Found jar in path: " + path);
                    URL url = new File(path).toURI().toURL();
                    urls.add(url);
                    LOG.debug("Using URL: " + url.toString());
                } catch (MalformedURLException e) {
                    throw new SqoopException(CoreError.CORE_0009, "Malformed URL found.", e);
                }
            }
        }

        return urls;
    }

    private synchronized void configureLogging() {
        Properties props = new Properties();
        for (Map.Entry<String, String> entry : config.entrySet()) {
            String key = entry.getKey();
            if (key.startsWith(ConfigurationConstants.PREFIX_LOG_CONFIG)) {
                String logConfigKey = key.substring(ConfigurationConstants.PREFIX_GLOBAL_CONFIG.length());
                props.put(logConfigKey, entry.getValue());
            }
        }

        if (props.isEmpty()) {
            LOG.info("Skipping log4j configuration as it's not configured in sqoop.properties file.");
            return;
        }

        PropertyConfigurator.configure(props);
    }

    public ConfigurationProvider getProvider() {
        return provider;
    }

    @Override
    public synchronized void configurationChanged() {
        oldConfig = config;
        config = provider.getConfiguration();
        configureLogging();
    }

    public static class CoreConfigurationListener implements ConfigurationListener {

        private Reconfigurable listener;

        public CoreConfigurationListener(Reconfigurable target) {
            listener = target;
        }

        @Override
        public void configurationChanged() {
            listener.configurationChanged();
        }
    }
}