org.apache.sqoop.repository.JdbcRepositoryProvider.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.sqoop.repository.JdbcRepositoryProvider.java

Source

/**
 * 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.sqoop.repository;

import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;

import javax.sql.DataSource;

import org.apache.commons.dbcp.ConnectionFactory;
import org.apache.commons.dbcp.DriverManagerConnectionFactory;
import org.apache.commons.dbcp.PoolableConnectionFactory;
import org.apache.commons.dbcp.PoolingDataSource;
import org.apache.commons.pool.KeyedObjectPoolFactory;
import org.apache.commons.pool.impl.GenericKeyedObjectPoolFactory;
import org.apache.commons.pool.impl.GenericObjectPool;
import org.apache.log4j.Logger;
import org.apache.sqoop.common.SqoopException;
import org.apache.sqoop.common.MapContext;
import org.apache.sqoop.core.SqoopConfiguration;
import org.apache.sqoop.utils.ClassUtils;

public class JdbcRepositoryProvider implements RepositoryProvider {

    private static final Logger LOG = Logger.getLogger(JdbcRepositoryProvider.class);

    private JdbcRepositoryContext repoContext;

    private Driver driver;
    private GenericObjectPool connectionPool;
    private KeyedObjectPoolFactory statementPool;
    private DataSource dataSource;

    private JdbcRepositoryHandler handler;
    private JdbcRepositoryTransactionFactory txFactory;
    private JdbcRepository repository;

    public JdbcRepositoryProvider() {
        // Default constructor
    }

    @Override
    public synchronized void initialize(MapContext context) {
        repoContext = new JdbcRepositoryContext(SqoopConfiguration.getInstance().getContext());

        initializeRepositoryHandler();

        LOG.info("JdbcRepository initialized.");
    }

    @Override
    public synchronized void destroy() {
        try {
            connectionPool.close();
        } catch (Exception ex) {
            LOG.error("Failed to shutdown connection pool", ex);
        }

        handler.shutdown();

        if (driver != null) {
            try {
                LOG.info("Deregistering JDBC driver");
                DriverManager.deregisterDriver(driver);
            } catch (SQLException ex) {
                LOG.error("Failed to deregister driver", ex);
            }
        }
        handler = null;
        driver = null;
        dataSource = null;
    }

    private void initializeRepositoryHandler() {
        String jdbcHandlerClassName = repoContext.getHandlerClassName();

        Class<?> handlerClass = ClassUtils.loadClass(jdbcHandlerClassName);

        if (handlerClass == null) {
            throw new SqoopException(RepositoryError.JDBCREPO_0001, jdbcHandlerClassName);
        }

        try {
            handler = (JdbcRepositoryHandler) handlerClass.newInstance();
        } catch (Exception ex) {
            throw new SqoopException(RepositoryError.JDBCREPO_0001, jdbcHandlerClassName, ex);
        }

        String connectUrl = repoContext.getConnectionUrl();
        if (connectUrl == null || connectUrl.trim().length() == 0) {
            throw new SqoopException(RepositoryError.JDBCREPO_0002);
        }

        String jdbcDriverClassName = repoContext.getDriverClass();
        if (jdbcDriverClassName == null || jdbcDriverClassName.trim().length() == 0) {
            throw new SqoopException(RepositoryError.JDBCREPO_0003);
        }

        // Initialize a datasource
        Class<?> driverClass = ClassUtils.loadClass(jdbcDriverClassName);

        if (driverClass == null) {
            throw new SqoopException(RepositoryError.JDBCREPO_0003, jdbcDriverClassName);
        }

        try {
            driver = (Driver) driverClass.newInstance();
        } catch (Exception ex) {
            throw new SqoopException(RepositoryError.JDBCREPO_0003, jdbcDriverClassName, ex);
        }

        Properties jdbcProps = repoContext.getConnectionProperties();

        ConnectionFactory connFactory = new DriverManagerConnectionFactory(connectUrl, jdbcProps);

        connectionPool = new GenericObjectPool();
        connectionPool.setMaxActive(repoContext.getMaximumConnections());

        statementPool = new GenericKeyedObjectPoolFactory(null);

        // creating the factor automatically wires the connection pool
        new PoolableConnectionFactory(connFactory, connectionPool, statementPool, handler.validationQuery(), false,
                false, repoContext.getTransactionIsolation().getCode());

        dataSource = new PoolingDataSource(connectionPool);
        txFactory = new JdbcRepositoryTransactionFactory(dataSource);

        repoContext.initialize(dataSource, txFactory);

        handler.initialize(repoContext);

        repository = new JdbcRepository(handler, repoContext);

        LOG.info("JdbcRepositoryProvider initialized");
    }

    @Override
    public synchronized Repository getRepository() {
        return repository;
    }

    @Override
    public void configurationChanged() {
        LOG.info("Begin JdbcRepository reconfiguring.");
        JdbcRepositoryContext oldRepoContext = repoContext;
        repoContext = new JdbcRepositoryContext(SqoopConfiguration.getInstance().getContext());

        // reconfigure jdbc handler
        String newJdbcHandlerClassName = repoContext.getHandlerClassName();
        if (newJdbcHandlerClassName == null || newJdbcHandlerClassName.trim().length() == 0) {
            throw new SqoopException(RepositoryError.JDBCREPO_0001, newJdbcHandlerClassName);
        }

        String oldJdbcHandlerClassName = oldRepoContext.getHandlerClassName();
        if (!newJdbcHandlerClassName.equals(oldJdbcHandlerClassName)) {
            LOG.warn("Repository JDBC handler cannot be replaced at the runtime. "
                    + "You might need to restart the server.");
        }

        // reconfigure jdbc driver
        String newJdbcDriverClassName = repoContext.getDriverClass();
        if (newJdbcDriverClassName == null || newJdbcDriverClassName.trim().length() == 0) {
            throw new SqoopException(RepositoryError.JDBCREPO_0003, newJdbcDriverClassName);
        }

        String oldJdbcDriverClassName = oldRepoContext.getDriverClass();
        if (!newJdbcDriverClassName.equals(oldJdbcDriverClassName)) {
            LOG.warn("Repository JDBC driver cannot be replaced at the runtime. "
                    + "You might need to restart the server.");
        }

        // reconfigure max connection
        connectionPool.setMaxActive(repoContext.getMaximumConnections());

        // reconfigure the url of repository
        String connectUrl = repoContext.getConnectionUrl();
        String oldurl = oldRepoContext.getConnectionUrl();
        if (connectUrl != null && !connectUrl.equals(oldurl)) {
            LOG.warn(
                    "Repository URL cannot be replaced at the runtime. " + "You might need to restart the server.");
        }

        // if connection properties or transaction isolation option changes
        boolean connFactoryChanged = false;

        // compare connection properties
        if (!connFactoryChanged) {
            Properties oldProp = oldRepoContext.getConnectionProperties();
            Properties newProp = repoContext.getConnectionProperties();

            if (newProp.size() != oldProp.size()) {
                connFactoryChanged = true;
            } else {
                for (Object key : newProp.keySet()) {
                    if (!newProp.getProperty((String) key).equals(oldProp.getProperty((String) key))) {
                        connFactoryChanged = true;
                        break;
                    }
                }
            }
        }

        // compare the transaction isolation option
        if (!connFactoryChanged) {
            String oldTxOption = oldRepoContext.getTransactionIsolation().toString();
            String newTxOption = repoContext.getTransactionIsolation().toString();

            if (!newTxOption.equals(oldTxOption)) {
                connFactoryChanged = true;
            }
        }

        if (connFactoryChanged) {
            // try to reconfigure connection factory
            try {
                LOG.info("Reconfiguring Connection Factory.");
                Properties jdbcProps = repoContext.getConnectionProperties();

                ConnectionFactory connFactory = new DriverManagerConnectionFactory(connectUrl, jdbcProps);

                new PoolableConnectionFactory(connFactory, connectionPool, statementPool, handler.validationQuery(),
                        false, false, repoContext.getTransactionIsolation().getCode());
            } catch (IllegalStateException ex) {
                // failed to reconfigure connection factory
                LOG.warn("Repository connection cannot be reconfigured currently. "
                        + "You might need to restart the server.");
            }
        }

        // ignore the create schema option, because the repo url is not allowed to change

        LOG.info("JdbcRepository reconfigured.");
    }
}