Commit 143f2103 by Suma Shivaprasad

ATLAS-232 Fix the API incompatibility introduced in ATLAS-58 (shwetags via sumasai)

parent bbf48d90
......@@ -67,7 +67,6 @@ public class AtlasClient {
public static final String BASE_URI = "api/atlas/";
public static final String TYPES = "types";
public static final String URI_ENTITY = "entity";
public static final String URI_ENTITIES = "entities";
public static final String URI_SEARCH = "discovery/search";
public static final String URI_LINEAGE = "lineage/hive/table";
......@@ -138,10 +137,10 @@ public class AtlasClient {
LIST_TRAIT_TYPES(BASE_URI + TYPES + "?type=trait", HttpMethod.GET),
//Entity operations
CREATE_ENTITY(BASE_URI + URI_ENTITIES, HttpMethod.POST),
CREATE_ENTITY(BASE_URI + URI_ENTITY, HttpMethod.POST),
GET_ENTITY(BASE_URI + URI_ENTITY, HttpMethod.GET),
UPDATE_ENTITY(BASE_URI + URI_ENTITY, HttpMethod.PUT),
LIST_ENTITIES(BASE_URI + URI_ENTITIES, HttpMethod.GET),
LIST_ENTITIES(BASE_URI + URI_ENTITY, HttpMethod.GET),
//Trait operations
ADD_TRAITS(BASE_URI + URI_ENTITY, HttpMethod.POST),
......
......@@ -9,7 +9,8 @@ ATLAS-54 Rename configs in hive hook (shwethags)
ATLAS-3 Mixed Index creation fails with Date types (sumasai via shwethags)
ALL CHANGES:
ATLAS1-98 Atlas UI Requires Internet Access(sanjayp via sumasai)
ATLAS-232 Fix the API incompatibility introduced in ATLAS-58(shwethags via sumasai)
ATLAS-198 Atlas UI Requires Internet Access(sanjayp via sumasai)
ATLAS-201 Rename org.apache.atlas.Main to org.apache.atlas.Atlas (rishabhbhardwaj via shwethags)
ATLAS-179 Atlas hook causes mem leak and hive server 2 crashes (shwethags)
ATLAS-212 Remove test class usage of hive configuration property "atlas.rest.address" (jspeidel via shwethags)
......
/**
* 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.google.common.base.Preconditions;
import com.google.inject.Inject;
import org.apache.atlas.AtlasClient;
import org.apache.atlas.AtlasException;
import org.apache.atlas.repository.EntityExistsException;
import org.apache.atlas.services.MetadataService;
import org.apache.atlas.typesystem.types.ValueConversionException;
import org.apache.atlas.web.util.Servlets;
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.Path;
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.Response;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
import java.net.URI;
import java.util.List;
@Path("entities")
@Singleton
public class EntitiesResource {
private static final Logger LOG = LoggerFactory.getLogger(EntitiesResource.class);
@Inject
private MetadataService metadataService;
@Context
UriInfo uriInfo;
/**
* Submits the entity definitions (instances).
* The body contains the JSONArray of entity json. The service takes care of de-duping the entities based on any
* unique attribute for the give type.
*/
@POST
@Consumes(Servlets.JSON_MEDIA_TYPE)
@Produces(Servlets.JSON_MEDIA_TYPE)
public Response submit(@Context HttpServletRequest request) {
try {
final String entities = Servlets.getRequestPayload(request);
LOG.debug("submitting entities {} ", AtlasClient.toString(new JSONArray(entities)));
final String guids = metadataService.createEntities(entities);
UriBuilder ub = uriInfo.getAbsolutePathBuilder();
URI locationURI = ub.path(guids).build();
JSONObject response = new JSONObject();
response.put(AtlasClient.REQUEST_ID, Servlets.getRequestId());
response.put(AtlasClient.GUID, new JSONArray(guids));
response.put(AtlasClient.DEFINITION, metadataService.getEntityDefinition(new JSONArray(guids).getString(0)));
return Response.created(locationURI).entity(response).build();
} catch(EntityExistsException e) {
LOG.error("Unique constraint violation", e);
throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.CONFLICT));
} catch (ValueConversionException ve) {
LOG.error("Unable to persist entity instance due to a desrialization error ", ve);
throw new WebApplicationException(Servlets.getErrorResponse(ve.getCause(), Response.Status.BAD_REQUEST));
} catch (AtlasException | IllegalArgumentException e) {
LOG.error("Unable to persist entity instance", e);
throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.BAD_REQUEST));
} catch (Throwable e) {
LOG.error("Unable to persist entity instance", e);
throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
}
}
/**
* Gets the list of entities for a given entity type.
*
* @param entityType name of a type which is unique
*/
@GET
@Produces(Servlets.JSON_MEDIA_TYPE)
public Response getEntityListByType(@QueryParam("type") String entityType) {
try {
Preconditions.checkNotNull(entityType, "Entity type cannot be null");
LOG.debug("Fetching entity list for type={} ", entityType);
final List<String> entityList = metadataService.getEntityList(entityType);
JSONObject response = new JSONObject();
response.put(AtlasClient.REQUEST_ID, Servlets.getRequestId());
response.put(AtlasClient.TYPENAME, entityType);
response.put(AtlasClient.RESULTS, new JSONArray(entityList));
response.put(AtlasClient.COUNT, entityList.size());
return Response.ok(response).build();
} catch (NullPointerException e) {
LOG.error("Entity type cannot be null", e);
throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.BAD_REQUEST));
} catch (AtlasException | IllegalArgumentException e) {
LOG.error("Unable to get entity list for type {}", entityType, e);
throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.BAD_REQUEST));
} catch (Throwable e) {
LOG.error("Unable to get entity list for type {}", entityType, e);
throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
}
}
}
......@@ -23,10 +23,14 @@ import org.apache.atlas.AtlasClient;
import org.apache.atlas.AtlasException;
import org.apache.atlas.ParamChecker;
import org.apache.atlas.TypeNotFoundException;
import org.apache.atlas.repository.EntityExistsException;
import org.apache.atlas.repository.EntityNotFoundException;
import org.apache.atlas.services.MetadataService;
import org.apache.atlas.typesystem.types.ValueConversionException;
import org.apache.atlas.web.util.Servlets;
import org.apache.commons.lang.StringUtils;
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -83,6 +87,57 @@ public class EntityResource {
/**
* Submits the entity definitions (instances).
* The body contains the JSONArray of entity json. The service takes care of de-duping the entities based on any
* unique attribute for the give type.
*/
@POST
@Consumes(Servlets.JSON_MEDIA_TYPE)
@Produces(Servlets.JSON_MEDIA_TYPE)
public Response submit(@Context HttpServletRequest request) {
try {
String entities = Servlets.getRequestPayload(request);
//Handle backward compatibility - if entities is not JSONArray, convert to JSONArray
try {
new JSONArray(entities);
} catch (JSONException e) {
final String finalEntities = entities;
entities = new JSONArray() {{
put(finalEntities);
}}.toString();
}
LOG.debug("submitting entities {} ", AtlasClient.toString(new JSONArray(entities)));
final String guids = metadataService.createEntities(entities);
UriBuilder ub = uriInfo.getAbsolutePathBuilder();
URI locationURI = ub.path(guids).build();
JSONObject response = new JSONObject();
response.put(AtlasClient.REQUEST_ID, Servlets.getRequestId());
response.put(AtlasClient.GUID, new JSONArray(guids));
response.put(AtlasClient.DEFINITION, metadataService.getEntityDefinition(new JSONArray(guids).getString(0)));
return Response.created(locationURI).entity(response).build();
} catch(EntityExistsException e) {
LOG.error("Unique constraint violation", e);
throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.CONFLICT));
} catch (ValueConversionException ve) {
LOG.error("Unable to persist entity instance due to a desrialization error ", ve);
throw new WebApplicationException(Servlets.getErrorResponse(ve.getCause(), Response.Status.BAD_REQUEST));
} catch (AtlasException | IllegalArgumentException e) {
LOG.error("Unable to persist entity instance", e);
throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.BAD_REQUEST));
} catch (Throwable e) {
LOG.error("Unable to persist entity instance", e);
throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
}
}
/**
* Fetch the complete definition of an entity given its GUID.
*
* @param guid GUID for the entity
......@@ -124,20 +179,61 @@ public class EntityResource {
}
/**
* Gets the list of entities for a given entity type.
*
* @param entityType name of a type which is unique
*/
public Response getEntityListByType(String entityType) {
try {
Preconditions.checkNotNull(entityType, "Entity type cannot be null");
LOG.debug("Fetching entity list for type={} ", entityType);
final List<String> entityList = metadataService.getEntityList(entityType);
JSONObject response = new JSONObject();
response.put(AtlasClient.REQUEST_ID, Servlets.getRequestId());
response.put(AtlasClient.TYPENAME, entityType);
response.put(AtlasClient.RESULTS, new JSONArray(entityList));
response.put(AtlasClient.COUNT, entityList.size());
return Response.ok(response).build();
} catch (NullPointerException e) {
LOG.error("Entity type cannot be null", e);
throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.BAD_REQUEST));
} catch (AtlasException | IllegalArgumentException e) {
LOG.error("Unable to get entity list for type {}", entityType, e);
throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.BAD_REQUEST));
} catch (Throwable e) {
LOG.error("Unable to get entity list for type {}", entityType, e);
throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
}
}
@GET
@Produces(Servlets.JSON_MEDIA_TYPE)
public Response getEntity(@QueryParam("type") String entityType,
@QueryParam("property") String attribute,
@QueryParam("value") String value) {
if (StringUtils.isEmpty(attribute)) {
//List API
return getEntityListByType(entityType);
} else {
//Get entity by unique attribute
return getEntityDefinitionByAttribute(entityType, attribute, value);
}
}
/**
* Fetch the complete definition of an entity given its qualified name.
*
* @param entityType
* @param attribute
* @param value
*/
@GET
@Produces(Servlets.JSON_MEDIA_TYPE)
public Response getEntityDefinitionByAttribute(@QueryParam("type") String entityType,
@QueryParam("property") String attribute,
@QueryParam("value") String value) {
public Response getEntityDefinitionByAttribute(String entityType, String attribute, String value) {
try {
LOG.debug("Fetching entity definition for type={}, qualified name={}", entityType, value);
ParamChecker.notEmpty(entityType, "type cannot be null");
ParamChecker.notEmpty(entityType, "Entity type cannot be null");
ParamChecker.notEmpty(attribute, "attribute name cannot be null");
ParamChecker.notEmpty(value, "attribute value cannot be null");
......
......@@ -91,6 +91,26 @@ public class EntityJerseyResourceIT extends BaseResourceIT {
}
}
@Test
public void testSubmitSingleEntity() throws Exception {
Referenceable databaseInstance = new Referenceable(DATABASE_TYPE);
databaseInstance.set("name", randomString());
databaseInstance.set("description", randomString());
ClientResponse clientResponse =
service.path("api/atlas/entity").accept(Servlets.JSON_MEDIA_TYPE).type(Servlets.JSON_MEDIA_TYPE)
.method(HttpMethod.POST, ClientResponse.class,
InstanceSerialization.toJson(databaseInstance, true));
Assert.assertEquals(clientResponse.getStatus(), Response.Status.CREATED.getStatusCode());
String responseAsString = clientResponse.getEntity(String.class);
Assert.assertNotNull(responseAsString);
JSONObject response = new JSONObject(responseAsString);
Assert.assertNotNull(response.get(AtlasClient.REQUEST_ID));
Assert.assertNotNull(response.get(AtlasClient.GUID));
}
@DataProvider
public Object[][] invalidAttrValues() {
return new Object[][]{{null}, {""}};
......@@ -264,7 +284,7 @@ public class EntityJerseyResourceIT extends BaseResourceIT {
@Test
public void testGetEntityListForBadEntityType() throws Exception {
ClientResponse clientResponse =
service.path("api/atlas/entities").queryParam("type", "blah").accept(Servlets.JSON_MEDIA_TYPE)
service.path("api/atlas/entity").queryParam("type", "blah").accept(Servlets.JSON_MEDIA_TYPE)
.type(Servlets.JSON_MEDIA_TYPE).method(HttpMethod.GET, ClientResponse.class);
Assert.assertEquals(clientResponse.getStatus(), Response.Status.BAD_REQUEST.getStatusCode());
......@@ -282,7 +302,7 @@ public class EntityJerseyResourceIT extends BaseResourceIT {
String typeName = addNewType();
ClientResponse clientResponse =
service.path("api/atlas/entities").queryParam("type", typeName).accept(Servlets.JSON_MEDIA_TYPE)
service.path("api/atlas/entity").queryParam("type", typeName).accept(Servlets.JSON_MEDIA_TYPE)
.type(Servlets.JSON_MEDIA_TYPE).method(HttpMethod.GET, ClientResponse.class);
Assert.assertEquals(clientResponse.getStatus(), Response.Status.OK.getStatusCode());
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment