Package org.apache.ambari.server.controller.jdbc

Source Code of org.apache.ambari.server.controller.jdbc.JDBCResourceProvider

/**
* 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.ambari.server.controller.jdbc;

import org.apache.ambari.server.controller.internal.BaseProvider;
import org.apache.ambari.server.controller.internal.RequestStatusImpl;
import org.apache.ambari.server.controller.internal.ResourceImpl;
import org.apache.ambari.server.controller.predicate.BasePredicate;
import org.apache.ambari.server.controller.predicate.PredicateVisitorAcceptor;
import org.apache.ambari.server.controller.spi.*;
import org.apache.ambari.server.controller.utilities.PredicateHelper;
import org.apache.ambari.server.controller.utilities.PropertyHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
* Generic JDBC based resource provider.
* TODO : Not used. Move to Test for API integration testing.
*/
public class JDBCResourceProvider extends BaseProvider implements ResourceProvider {

    private final Resource.Type type;

  private final ConnectionFactory connectionFactory;

    /**
     * The schema for this provider's resource type.
     */
    private final Map<Resource.Type, String> keyPropertyIds;

    /**
     * Key mappings used for joins.
     */
    private final Map<String, Map<String, String>> importedKeys = new HashMap<String, Map<String, String>>();

    protected final static Logger LOG =
            LoggerFactory.getLogger(JDBCResourceProvider.class);

    public JDBCResourceProvider(ConnectionFactory connectionFactory,
                                Resource.Type type,
                                Set<String> propertyIds,
                                Map<Resource.Type, String> keyPropertyIds) {
      super(propertyIds);
      this.connectionFactory = connectionFactory;
      this.type = type;
      this.keyPropertyIds = keyPropertyIds;
    }

    @Override
    public Set<Resource> getResources(Request request, Predicate predicate)
        throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {

        Set<Resource> resources = new HashSet<Resource>();
        Set<String> propertyIds = getRequestPropertyIds(request, predicate);

        // Can't allow these properties with the old schema...
        propertyIds.remove(PropertyHelper.getPropertyId("Clusters", "cluster_id"));
        propertyIds.remove(PropertyHelper.getPropertyId("Hosts", "disk_info"));
        propertyIds.remove(PropertyHelper.getPropertyId("Hosts", "public_host_name"));
        propertyIds.remove(PropertyHelper.getPropertyId("Hosts", "last_registration_time"));
        propertyIds.remove(PropertyHelper.getPropertyId("Hosts", "host_state"));
        propertyIds.remove(PropertyHelper.getPropertyId("Hosts", "last_heartbeat_time"));
        propertyIds.remove(PropertyHelper.getPropertyId("Hosts", "host_health_report"));
        propertyIds.remove(PropertyHelper.getPropertyId("Hosts", "host_status"));
        propertyIds.remove(PropertyHelper.getPropertyId("ServiceInfo", "desired_configs"));
        propertyIds.remove(PropertyHelper.getPropertyId("ServiceComponentInfo", "desired_configs"));
        propertyIds.remove(PropertyHelper.getPropertyId("HostRoles", "configs"));
        propertyIds.remove(PropertyHelper.getPropertyId("HostRoles", "desired_configs"));

        Connection connection = null;
        Statement statement = null;
        ResultSet rs = null;
        try {
            connection = connectionFactory.getConnection();


            for (String table : getTables(propertyIds)) {
                getImportedKeys(connection, table);
            }

            String sql = getSelectSQL(propertyIds, predicate);
            statement = connection.createStatement();

            rs = statement.executeQuery(sql);

            while (rs.next()) {
                ResultSetMetaData metaData = rs.getMetaData();
                int columnCount = metaData.getColumnCount();

                final ResourceImpl resource = new ResourceImpl(type);
                for (int i = 1; i <= columnCount; ++i) {
                    String propertyId = PropertyHelper.getPropertyId(metaData.getTableName(i), metaData.getColumnName(i));
                    if (propertyIds.contains(propertyId)) {
                        resource.setProperty(propertyId, rs.getString(i));
                    }
                }
                resources.add(resource);
            }
            statement.close();

        } catch (SQLException e) {
            if (LOG.isDebugEnabled()) {
                LOG.debug("Caught exception getting resource.", e);
            }
            return Collections.emptySet();
        } finally {
            try {
                if (rs != null) rs.close();
            } catch (SQLException e) {
                LOG.error("Exception while closing ResultSet", e);
            }

            try {
                if (statement != null) statement.close();
            } catch (SQLException e) {
                LOG.error("Exception while closing statment", e);
            }

            try {
                if (connection != null) connection.close();
            } catch (SQLException e) {
                LOG.error("Exception while closing statment", e);
            }

        }


        return resources;
    }

    @Override
    public RequestStatus createResources(Request request)
        throws SystemException,
               UnsupportedPropertyException,
               ResourceAlreadyExistsException,
               NoSuchParentResourceException {

        try {
            Connection connection = connectionFactory.getConnection();

            try {

                Set<Map<String, Object>> propertySet = request.getProperties();

                for (Map<String, Object> properties : propertySet) {
                    String sql = getInsertSQL(properties);

                    Statement statement = connection.createStatement();

                    statement.execute(sql);

                    statement.close();
                }
            } finally {
                connection.close();
            }

        } catch (SQLException e) {
            throw new IllegalStateException("DB error : ", e);
        }

        return getRequestStatus();
    }

    @Override
    public RequestStatus updateResources(Request request, Predicate predicate)
        throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {

        try {
            Connection connection = connectionFactory.getConnection();
            try {
                Set<Map<String, Object>> propertySet = request.getProperties();

                Map<String, Object> properties = propertySet.iterator().next();

                String sql = getUpdateSQL(properties, predicate);

                Statement statement = connection.createStatement();

                statement.execute(sql);

                statement.close();
            } finally {
                connection.close();
            }

        } catch (SQLException e) {
            throw new IllegalStateException("DB error : ", e);
        }

        return getRequestStatus();
    }

    @Override
    public RequestStatus deleteResources(Predicate predicate)
        throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {

        try {
            Connection connection = connectionFactory.getConnection();
            try {
                String sql = getDeleteSQL(predicate);

                Statement statement = connection.createStatement();
                statement.execute(sql);
                statement.close();
            } finally {
                connection.close();
            }

        } catch (SQLException e) {
            throw new IllegalStateException("DB error : ", e);
        }

        return getRequestStatus();
    }


    private String getInsertSQL(Map<String, Object> properties) {

        StringBuilder columns = new StringBuilder();
        StringBuilder values = new StringBuilder();
        String table = null;


        for (Map.Entry<String, Object> entry : properties.entrySet()) {
            String propertyId = entry.getKey();
            Object propertyValue = entry.getValue();

            table = PropertyHelper.getPropertyCategory(propertyId);


            if (columns.length() > 0) {
                columns.append(", ");
            }
            columns.append(PropertyHelper.getPropertyName(propertyId));

            if (values.length() > 0) {
                values.append(", ");
            }
            values.append("'");
            values.append(propertyValue);
            values.append("'");
        }

        return "insert into " + table + " (" +
                columns + ") values (" + values + ")";
    }

    private String getSelectSQL(Set<String> propertyIds, Predicate predicate) {

        StringBuilder columns = new StringBuilder();
        Set<String> tableSet = new HashSet<String>();

        for (String propertyId : propertyIds) {
            if (columns.length() > 0) {
                columns.append(", ");
            }
          String propertyCategory = PropertyHelper.getPropertyCategory(propertyId);
          columns.append(propertyCategory).append(".").append(PropertyHelper.getPropertyName(propertyId));
            tableSet.add(propertyCategory);
        }


        boolean haveWhereClause = false;
        StringBuilder whereClause = new StringBuilder();
        if (predicate != null &&
                propertyIds.containsAll(PredicateHelper.getPropertyIds(predicate)) &&
                predicate instanceof PredicateVisitorAcceptor) {

            SQLPredicateVisitor visitor = new SQLPredicateVisitor();
            ((PredicateVisitorAcceptor) predicate).accept(visitor);
            whereClause.append(visitor.getSQL());
            haveWhereClause = true;
        }

        StringBuilder joinClause = new StringBuilder();

        if (tableSet.size() > 1) {

            for (String table : tableSet) {
                Map<String, String> joinKeys = importedKeys.get(table);
                if (joinKeys != null) {
                    for (Map.Entry<String, String> entry : joinKeys.entrySet()) {
                        String category1 = PropertyHelper.getPropertyCategory(entry.getKey());
                        String category2 = PropertyHelper.getPropertyCategory(entry.getValue());
                        if (tableSet.contains(category1) && tableSet.contains(category2)) {
                            if (haveWhereClause) {
                                joinClause.append(" AND ");
                            }
                            joinClause.append(category1).append(".").append(PropertyHelper.getPropertyName(entry.getKey()));
                            joinClause.append(" = ");
                            joinClause.append(category2).append(".").append(PropertyHelper.getPropertyName(entry.getValue()));
                            tableSet.add(category1);
                            tableSet.add(category2);

                            haveWhereClause = true;
                        }
                    }
                }
            }
        }

        StringBuilder tables = new StringBuilder();

        for (String table : tableSet) {
            if (tables.length() > 0) {
                tables.append(", ");
            }
            tables.append(table);
        }

        String sql = "select " + columns + " from " + tables;

        if (haveWhereClause) {
            sql = sql + " where " + whereClause + joinClause;
        }

        return sql;
    }

    private String getDeleteSQL(Predicate predicate) {

        StringBuilder whereClause = new StringBuilder();
        if (predicate instanceof BasePredicate) {

            BasePredicate basePredicate = (BasePredicate) predicate;

            SQLPredicateVisitor visitor = new SQLPredicateVisitor();
            basePredicate.accept(visitor);
            whereClause.append(visitor.getSQL());

            String table = PropertyHelper.getPropertyCategory(basePredicate.getPropertyIds().iterator().next());

            return "delete from " + table + " where " + whereClause;
        }
        throw new IllegalStateException("Can't generate SQL.");
    }

    private String getUpdateSQL(Map<String, Object> properties, Predicate predicate) {

        if (predicate instanceof BasePredicate) {

            StringBuilder whereClause = new StringBuilder();

            BasePredicate basePredicate = (BasePredicate) predicate;

            SQLPredicateVisitor visitor = new SQLPredicateVisitor();
            basePredicate.accept(visitor);
            whereClause.append(visitor.getSQL());

            String table = PropertyHelper.getPropertyCategory(basePredicate.getPropertyIds().iterator().next());


            StringBuilder setClause = new StringBuilder();
            for (Map.Entry<String, Object> entry : properties.entrySet()) {

                if (setClause.length() > 0) {
                    setClause.append(", ");
                }
                setClause.append(PropertyHelper.getPropertyName(entry.getKey()));
                setClause.append(" = ");
                setClause.append("'");
                setClause.append(entry.getValue());
                setClause.append("'");
            }

            return "update " + table + " set " + setClause + " where " + whereClause;
        }
        throw new IllegalStateException("Can't generate SQL.");
    }

    @Override
    public Map<Resource.Type, String> getKeyPropertyIds() {
        return keyPropertyIds;
    }

    /**
     * Lazily populate the imported key mappings for the given table.
     *
     * @param connection the connection to use to obtain the database meta data
     * @param table      the table
     * @throws SQLException thrown if the meta data for the given connection cannot be obtained
     */
    private void getImportedKeys(Connection connection, String table) throws SQLException {
        if (!this.importedKeys.containsKey(table)) {

            Map<String, String> importedKeys = new HashMap<String, String>();
            this.importedKeys.put(table, importedKeys);

            DatabaseMetaData metaData = connection.getMetaData();

            ResultSet rs = metaData.getImportedKeys(connection.getCatalog(), null, table);

            while (rs.next()) {

                String pkPropertyId = PropertyHelper.getPropertyId(
                    rs.getString("PKTABLE_NAME"), rs.getString("PKCOLUMN_NAME"));

                String fkPropertyId = PropertyHelper.getPropertyId(
                    rs.getString("FKTABLE_NAME"), rs.getString("FKCOLUMN_NAME"));

                importedKeys.put(pkPropertyId, fkPropertyId);
            }
        }
    }

    /**
     * Get a request status
     *
     * @return the request status
     */
    private RequestStatus getRequestStatus() {
        return new RequestStatusImpl(null);
    }

    /**
     * Get the set of tables associated with the given property ids.
     *
     * @param propertyIds the property ids
     * @return the set of tables
     */
    private static Set<String> getTables(Set<String> propertyIds) {
        Set<String> tables = new HashSet<String>();
        for (String propertyId : propertyIds) {
            tables.add(PropertyHelper.getPropertyCategory(propertyId));
        }
        return tables;
    }
}
TOP

Related Classes of org.apache.ambari.server.controller.jdbc.JDBCResourceProvider

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.