content: /**
   * 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.atlas.web.resources;
  
  import com.sun.jersey.api.client.ClientResponse;
  import com.sun.jersey.api.core.ResourceContext;
  import org.apache.atlas.AtlasClient;
  import org.apache.atlas.exception.AtlasBaseException;
  import org.apache.atlas.model.typedef.AtlasTypesDef;
  import org.apache.atlas.repository.converters.TypeConverterUtil;
  import org.apache.atlas.store.AtlasTypeDefStore;
  import org.apache.atlas.type.AtlasTypeRegistry;
  import org.apache.atlas.utils.AtlasJson;
  import org.apache.atlas.utils.AtlasPerfTracer;
  import org.apache.atlas.v1.model.typedef.TypesDef;
  import org.apache.atlas.web.rest.TypesREST;
  import org.apache.atlas.web.util.Servlets;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  import org.springframework.stereotype.Service;
  
  import javax.inject.Inject;
  import javax.inject.Singleton;
  import javax.servlet.http.HttpServletRequest;
  import javax.ws.rs.Consumes;
  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.WebApplicationException;
  import javax.ws.rs.core.Context;
  import javax.ws.rs.core.MediaType;
  import javax.ws.rs.core.Response;
  
  import java.util.ArrayList;
  import java.util.Collections;
  import java.util.HashMap;
  import java.util.List;
  import java.util.Map;
  
  /**
   * This class provides RESTful API for Types.
   *
   * A type is the description of any representable item;
   * e.g. a Hive table
   *
   * You could represent any meta model representing any domain using these types.
   */
  @Path("types")
  @Singleton
  @Service
  @Deprecated
  public class TypesResource {
      private static final Logger LOG      = LoggerFactory.getLogger(TypesResource.class);
      private static final Logger PERF_LOG = AtlasPerfTracer.getPerfLogger("rest.TypesResource");
  
      private static AtlasTypeRegistry typeRegistry;
  
      private final TypesREST         typesREST;
      private final AtlasTypeDefStore typeDefStore;
  
      @Context
      private ResourceContext resourceContext;
  
      @Inject
      public TypesResource(AtlasTypeRegistry typeRegistry, TypesREST typesREST, AtlasTypeDefStore typeDefStore) {
          TypesResource.typeRegistry = typeRegistry;
  
          this.typesREST             = typesREST;
          this.typeDefStore = typeDefStore;
      }
  
      /**
       * Submits a type definition corresponding to a given type representing a meta model of a
       * domain. Could represent things like Hive Database, Hive Table, etc.
       */
      @POST
      @Consumes({Servlets.JSON_MEDIA_TYPE, MediaType.APPLICATION_JSON})
      @Produces(Servlets.JSON_MEDIA_TYPE)
      public Response submit(@Context HttpServletRequest request) {
          LOG.debug("==> TypesResource.submit()");
  
          AtlasPerfTracer perf = null;
  
          if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
              perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "TypesResource.submit()");
          }
  
          try {
              final String typeDefinition = Servlets.getRequestPayload(request);
  
              LOG.debug("Creating type with definition {} ", typeDefinition);
  
              AtlasTypesDef             createTypesDef  = TypeConverterUtil.toAtlasTypesDef(typeDefinition, typeRegistry);
              AtlasTypesDef             createdTypesDef = typesREST.createAtlasTypeDefs(createTypesDef);
              List<String>              typeNames       = TypeConverterUtil.getTypeNames(createdTypesDef);
              List<Map<String, Object>> typesResponse   = new ArrayList<>(typeNames.size());
  
              for (String typeName : typeNames) {
                  typesResponse.add(Collections.singletonMap(AtlasClient.NAME, typeName));
              }
  
              Map<String, Object> response = new HashMap<>();
  
              response.put(AtlasClient.REQUEST_ID, Servlets.getRequestId());
              response.put(AtlasClient.TYPES, typesResponse);
  
              return Response.status(ClientResponse.Status.CREATED).entity(AtlasJson.toV1Json(response)).build();
          } catch (AtlasBaseException e) {
              LOG.error("Type creation failed", e);
  
              throw new WebApplicationException(Servlets.getErrorResponse(e));
          } catch (IllegalArgumentException e) {
              LOG.error("Unable to persist types", e);
  
              throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.BAD_REQUEST));
          } catch (WebApplicationException e) {
              LOG.error("Unable to persist types", e);
  
              throw e;
          } catch (Throwable e) {
              LOG.error("Unable to persist types", e);
  
              throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
          } finally {
              AtlasPerfTracer.log(perf);
  
              LOG.debug("<== TypesResource.submit()");
          }
      }
  
      /**
       * Update of existing types - if the given type doesn't exist, creates new type
       * Allowed updates are:
       * 1. Add optional attribute
       * 2. Change required to optional attribute
       * 3. Add super types - super types shouldn't contain any required attributes
       * @param request
       * @return
       */
      @PUT
      @Consumes({Servlets.JSON_MEDIA_TYPE, MediaType.APPLICATION_JSON})
      @Produces(Servlets.JSON_MEDIA_TYPE)
      public Response update(@Context HttpServletRequest request) {
          LOG.debug("==> TypesResource.update()");
  
          AtlasPerfTracer perf = null;
  
          if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
              perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "TypesResource.update()");
          }
  
          try {
              final String typeDefinition = Servlets.getRequestPayload(request);
  
              LOG.debug("Updating type with definition {} ", typeDefinition);
  
              AtlasTypesDef             updateTypesDef  = TypeConverterUtil.toAtlasTypesDef(typeDefinition, typeRegistry);
              AtlasTypesDef             updatedTypesDef = typeDefStore.createUpdateTypesDef(updateTypesDef);
              List<String>              typeNames       = TypeConverterUtil.getTypeNames(updatedTypesDef);
              List<Map<String, Object>> typesResponse   = new ArrayList<>(typeNames.size());
  
              for (String typeName : typeNames) {
                  typesResponse.add(Collections.singletonMap(AtlasClient.NAME, typeName));
              }
  
              Map<String, Object> response = new HashMap<>();
  
              response.put(AtlasClient.REQUEST_ID, Servlets.getRequestId());
              response.put(AtlasClient.TYPES, typesResponse);
  
              return Response.ok().entity(AtlasJson.toV1Json(response)).build();
          } catch (AtlasBaseException e) {
              LOG.error("Unable to persist types", e);
  
              throw new WebApplicationException(Servlets.getErrorResponse(e));
          } catch (IllegalArgumentException e) {
              LOG.error("Unable to persist types", e);
  
              throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.BAD_REQUEST));
          } catch (WebApplicationException e) {
              LOG.error("Unable to persist types", e);
  
              throw e;
          } catch (Throwable e) {
              LOG.error("Unable to persist types", e);
  
              throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
          } finally {
              AtlasPerfTracer.log(perf);
  
              if (LOG.isDebugEnabled()) {
                  LOG.debug("<== TypesResource.update()");
              }
          }
      }
  
      /**
       * Fetch the complete definition of a given type name which is unique.
       *
       * @param typeName name of a type which is unique.
       */
      @GET
      @Path("{typeName}")
      @Produces(Servlets.JSON_MEDIA_TYPE)
      public Response getDefinition(@Context HttpServletRequest request, @PathParam("typeName") String typeName) {
          LOG.debug("==> TypesResource.getDefinition({})", typeName);
  
          AtlasPerfTracer perf = null;
  
          if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
              perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "TypesResource.getDefinition(" + typeName + ")");
          }
  
          Map<String, Object> response = new HashMap<>();
  
          try {
              TypesDef typesDef = TypeConverterUtil.toTypesDef(typeRegistry.getType(typeName), typeRegistry);
  
              response.put(AtlasClient.TYPENAME, typeName);
              response.put(AtlasClient.DEFINITION, typesDef);
              response.put(AtlasClient.REQUEST_ID, Servlets.getRequestId());
  
              return Response.ok(AtlasJson.toV1Json(response)).build();
          } catch (AtlasBaseException e) {
              LOG.error("Unable to get type definition for type {}", typeName, e);
  
              throw new WebApplicationException(Servlets.getErrorResponse(e));
          } catch (IllegalArgumentException e) {
              LOG.error("Unable to get type definition for type {}", typeName, e);
  
              throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.BAD_REQUEST));
          } catch (WebApplicationException e) {
              LOG.error("Unable to get type definition for type {}", typeName, e);
  
              throw e;
          } catch (Throwable e) {
              LOG.error("Unable to get type definition for type {}", typeName, e);
  
              throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
          } finally {
              AtlasPerfTracer.log(perf);
  
              LOG.debug("<== TypesResource.getDefinition({})", typeName);
          }
      }
  
      /**
       * Return the list of type names in the type system which match the specified filter.
       *
       * @return list of type names
       * @param typeCategory returns types whose relationshipCategory is the given typeCategory
       * @param supertype returns types which contain the given supertype
       * @param notsupertype returns types which do not contain the given supertype
       *
       * Its possible to specify combination of these filters in one request and the conditions are combined with AND
       * For example, typeCategory = TRAIT && supertype contains 'X' && supertype !contains 'Y'
       * If there is no filter, all the types are returned
       */
      @GET
      @Produces(Servlets.JSON_MEDIA_TYPE)
      public Response getTypesByFilter(@Context HttpServletRequest request, @QueryParam("type") String typeCategory, @QueryParam("supertype") String supertype, @QueryParam("notsupertype") String notsupertype) {
          LOG.debug("==> TypesResource.getTypesByFilter({}, {}, {})", typeCategory, supertype, notsupertype);
  
          AtlasPerfTracer perf = null;
  
          if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
              perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "TypesResource.getTypesByFilter(" + typeCategory + ", " + supertype + ", " + notsupertype + ")");
          }
  
          Map<String, Object> response = new HashMap<>();
  
          try {
              List<String> result = TypeConverterUtil.getTypeNames(typesREST.getTypeDefHeaders(request));
  
              response.put(AtlasClient.RESULTS, result);
              response.put(AtlasClient.COUNT, result.size());
              response.put(AtlasClient.REQUEST_ID, Servlets.getRequestId());
  
              return Response.ok(AtlasJson.toV1Json(response)).build();
          } catch (AtlasBaseException e) {
              LOG.warn("TypesREST exception: {} {}", e.getClass().getSimpleName(), e.getMessage());
  
              throw new WebApplicationException(Servlets.getErrorResponse(e));
          } catch (WebApplicationException e) {
              LOG.error("Unable to get types list", e);
  
              throw e;
          } catch (Throwable e) {
              LOG.error("Unable to get types list", e);
  
              throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
          } finally {
              AtlasPerfTracer.log(perf);
  
              LOG.debug("<== TypesResource.getTypesByFilter({}, {}, {})", typeCategory, supertype, notsupertype);
          }
      }
  }
  