/** * 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 * <p> * http://www.apache.org/licenses/LICENSE-2.0 * <p> * 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.view.hive20.resources.browser; import org.apache.ambari.view.hive20.BaseService; import org.apache.ambari.view.hive20.client.ConnectionConfig; import org.apache.ambari.view.hive20.exceptions.ServiceException; import org.apache.ambari.view.hive20.internal.dto.ColumnStats; import org.apache.ambari.view.hive20.internal.dto.DatabaseResponse; import org.apache.ambari.view.hive20.internal.dto.TableMeta; import org.apache.ambari.view.hive20.internal.dto.TableResponse; import org.apache.ambari.view.hive20.resources.jobs.viewJobs.Job; import org.apache.ambari.view.hive20.resources.jobs.viewJobs.JobResourceManager; import org.apache.ambari.view.hive20.utils.ServiceFormattedException; import org.apache.ambari.view.hive20.utils.SharedObjectsFactory; import org.apache.parquet.Strings; import org.json.simple.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.inject.Inject; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import java.util.Set; /** * Resource to get the DDL information for the database */ public class DDLService extends BaseService { private static final String CREATE_TABLE = "create-table"; private static final String ALTER_TABLE = "alter-table"; private final DDLProxy proxy; private JobResourceManager resourceManager; protected final static Logger LOG = LoggerFactory.getLogger(DDLService.class); protected synchronized JobResourceManager getResourceManager() { if (resourceManager == null) { SharedObjectsFactory connectionsFactory = getSharedObjectsFactory(); resourceManager = new JobResourceManager(connectionsFactory, context); } return resourceManager; } @Inject public DDLService(DDLProxy proxy) { this.proxy = proxy; } @GET @Path("databases") @Produces(MediaType.APPLICATION_JSON) public Response getDatabases(@QueryParam("like") String like) { Set<DatabaseResponse> infos = proxy.getDatabases(); JSONObject response = new JSONObject(); response.put("databases", infos); return Response.ok(response).build(); } @GET @Path("databases/{database_id}") @Produces(MediaType.APPLICATION_JSON) public Response getDatabase(@PathParam("database_id") String databaseId) { DatabaseResponse database = proxy.getDatabase(databaseId); JSONObject response = new JSONObject(); response.put("database", database); return Response.ok(response).build(); } @DELETE @Path("databases/{database_id}") @Produces(MediaType.APPLICATION_JSON) public Response deleteDatabase(@PathParam("database_id") String databaseId) { Job job = null; try { job = proxy.deleteDatabase(databaseId, getResourceManager()); JSONObject response = new JSONObject(); response.put("job", job); return Response.status(Response.Status.ACCEPTED).entity(response).build(); } catch (ServiceException e) { LOG.error("Exception occurred while delete database {}", databaseId, e); throw new ServiceFormattedException(e); } } @POST @Path("databases") @Produces(MediaType.APPLICATION_JSON) public Response createDatabase(CreateDatabaseRequestWrapper wrapper) { String databaseId = wrapper.database.name; Job job = null; try { job = proxy.createDatabase(databaseId, getResourceManager()); JSONObject response = new JSONObject(); response.put("job", job); return Response.status(Response.Status.ACCEPTED).entity(response).build(); } catch (ServiceException e) { LOG.error("Exception occurred while delete database {}", databaseId, e); throw new ServiceFormattedException(e); } } @GET @Path("databases/{database_id}/tables") @Produces(MediaType.APPLICATION_JSON) public Response getTables(@PathParam("database_id") String databaseName) { Set<TableResponse> tables = proxy.getTables(databaseName); JSONObject response = new JSONObject(); response.put("tables", tables); return Response.ok(response).build(); } @POST @Path("databases/{database_id}/tables") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) public Response createTable(@PathParam("database_id") String databaseName, TableMetaRequest request) { try { Job job = proxy.createTable(databaseName, request.tableInfo, getResourceManager()); JSONObject response = new JSONObject(); response.put("job", job); return Response.status(Response.Status.ACCEPTED).entity(response).build(); } catch (ServiceException e) { LOG.error("Exception occurred while creatint table for db {} with details : {}", databaseName, request.tableInfo, e); throw new ServiceFormattedException(e); } } @PUT @Path("databases/{database_id}/tables/{table_id}/rename") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) public Response renameTable(@PathParam("database_id") String oldDatabaseName, @PathParam("table_id") String oldTableName, TableRenameRequest request) { try { Job job = proxy.renameTable(oldDatabaseName, oldTableName, request.newDatabase, request.newTable, getResourceManager()); JSONObject response = new JSONObject(); response.put("job", job); return Response.status(Response.Status.ACCEPTED).entity(response).build(); } catch (ServiceException e) { LOG.error("Exception occurred while renaming table for oldDatabaseName {}, oldTableName: {}, newDatabaseName : {}," + " newTableName : {}", oldDatabaseName, oldTableName, request.newDatabase, request.newTable, e); throw new ServiceFormattedException(e); } } @PUT @Path("databases/{database_id}/tables/{table_id}/analyze") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) public Response analyzeTable(@PathParam("database_id") String databaseName, @PathParam("table_id") String tableName, @QueryParam("analyze_columns") String analyzeColumns) { Boolean shouldAnalyzeColumns = Boolean.FALSE; if(!Strings.isNullOrEmpty(analyzeColumns)){ shouldAnalyzeColumns = Boolean.valueOf(analyzeColumns.trim()); } try { ConnectionConfig hiveConnectionConfig = getHiveConnectionConfig(); Job job = proxy.analyzeTable(databaseName, tableName, shouldAnalyzeColumns, getResourceManager(), hiveConnectionConfig); JSONObject response = new JSONObject(); response.put("job", job); return Response.status(Response.Status.ACCEPTED).entity(response).build(); } catch (ServiceException e) { LOG.error("Exception occurred while analyzing table for database {}, table: {}, analyzeColumns: {}" , databaseName, tableName, analyzeColumns, e); throw new ServiceFormattedException(e); } } @POST @Path("databases/{database_id}/tables/ddl") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) public Response generateDDL(TableMetaRequest request, @QueryParam("query_type") String queryType) { try { String query = null; if (queryType.equals(CREATE_TABLE)) { query = proxy.generateCreateTableDDL(request.tableInfo.getDatabase(), request.tableInfo); }else if(queryType.equals(ALTER_TABLE)){ query = proxy.generateAlterTableQuery(context, getHiveConnectionConfig(), request.tableInfo.getDatabase(), request.tableInfo.getTable(), request.tableInfo); }else{ throw new ServiceException("query_type = '" + queryType + "' is not supported"); } JSONObject response = new JSONObject(); response.put("ddl", new DDL(query)); return Response.status(Response.Status.ACCEPTED).entity(response).build(); } catch (ServiceException e) { LOG.error("Exception occurred while generating {} ddl for : {}", queryType, request.tableInfo, e); throw new ServiceFormattedException(e); } } @GET @Path("databases/{database_id}/tables/{table_id}") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) public Response getTable(@PathParam("database_id") String databaseName, @PathParam("table_id") String tableName) { TableResponse table = proxy.getTable(databaseName, tableName); JSONObject response = new JSONObject(); response.put("table", table); return Response.ok(response).build(); } /** * * @param databaseName * @param oldTableName : this is required in case if the name of table itself is changed in tableMeta * @param tableMetaRequest * @return */ @PUT @Path("databases/{database_id}/tables/{table_id}") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) public Response alterTable(@PathParam("database_id") String databaseName, @PathParam("table_id") String oldTableName, TableMetaRequest tableMetaRequest) { try { ConnectionConfig hiveConnectionConfig = getHiveConnectionConfig(); Job job = proxy.alterTable(context, hiveConnectionConfig, databaseName, oldTableName, tableMetaRequest.tableInfo, getResourceManager()); JSONObject response = new JSONObject(); response.put("job", job); return Response.status(Response.Status.ACCEPTED).entity(response).build(); } catch (ServiceException e) { LOG.error("Exception occurred while creatint table for db {} with details : {}", databaseName, tableMetaRequest.tableInfo, e); throw new ServiceFormattedException(e); } } @DELETE @Path("databases/{database_id}/tables/{table_id}") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) public Response deleteTable(@PathParam("database_id") String databaseName, @PathParam("table_id") String tableName) { try { Job job = proxy.deleteTable(databaseName, tableName, getResourceManager()); JSONObject response = new JSONObject(); response.put("job", job); return Response.status(Response.Status.ACCEPTED).entity(response).build(); } catch (ServiceException e) { LOG.error("Exception occurred while deleting table for db {}, tableName : {}", databaseName, tableName, e); throw new ServiceFormattedException(e); } } @GET @Path("databases/{database_id}/tables/{table_id}/info") @Produces(MediaType.APPLICATION_JSON) public Response getTableInfo(@PathParam("database_id") String databaseName, @PathParam("table_id") String tableName) { ConnectionConfig hiveConnectionConfig = getHiveConnectionConfig(); TableMeta meta = proxy.getTableProperties(context, hiveConnectionConfig, databaseName, tableName); JSONObject response = new JSONObject(); response.put("tableInfo", meta); return Response.ok(response).build(); } @GET @Path("databases/{database_id}/tables/{table_id}/column/{column_id}/stats") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) public Response getColumnStats(@PathParam("database_id") String databaseName, @PathParam("table_id") String tableName, @PathParam("column_id") String columnName) { try { Job job = proxy.getColumnStatsJob(databaseName, tableName, columnName, getResourceManager()); JSONObject response = new JSONObject(); response.put("job", job); return Response.status(Response.Status.ACCEPTED).entity(response).build(); } catch (ServiceException e) { LOG.error("Exception occurred while fetching column stats", databaseName, tableName, e); throw new ServiceFormattedException(e); } } @GET @Path("databases/{database_id}/tables/{table_id}/column/{column_id}/fetch_stats") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) public Response fetchColumnStats(@PathParam("database_id") String databaseName, @PathParam("table_id") String tablename, @PathParam("column_id") String columnName, @QueryParam("job_id") String jobId) { try { ColumnStats columnStats = proxy.fetchColumnStats(columnName, jobId, context); columnStats.setTableName(tablename); columnStats.setDatabaseName(databaseName); JSONObject response = new JSONObject(); response.put("columnStats", columnStats); return Response.status(Response.Status.ACCEPTED).entity(response).build(); } catch (ServiceException e) { LOG.error("Exception occurred while fetching column stats for column: {} and jobId: {}", columnName, jobId, e); throw new ServiceFormattedException(e); } } public static class DDL { String query; public DDL(String query) { this.query = query; } } /** * Wrapper class for table meta request */ public static class TableMetaRequest { public TableMeta tableInfo; } /** * Wrapper class for create database request */ public static class CreateDatabaseRequestWrapper { public CreateDatabaseRequest database; } /** * Request class for create database */ public static class CreateDatabaseRequest { public String name; } /** * Wrapper class for table rename request */ public static class TableRenameRequest { /* New database name */ public String newDatabase; /* New table name */ public String newTable; } }