Skip to content

Commit

Permalink
Elide 5- Unify request ids (#1423)
Browse files Browse the repository at this point in the history
* Unified request ID for elide 5

* Fixing issues

* Fixed some tests

* Fixed build

* Removed Data Store Transaction changes for request ID

* Inspection rework

Co-authored-by: Aaron Klish <[email protected]>
  • Loading branch information
aklish and Aaron Klish authored Jul 8, 2020
1 parent 99bef6f commit 70ab71e
Show file tree
Hide file tree
Showing 39 changed files with 170 additions and 121 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ public class AsyncQuery extends AsyncBase implements PrincipalOwned {
@ComputedAttribute
private Integer asyncAfterSeconds = 10;

private String requestId; //Client provided
@Exclude
private String requestId = UUID.randomUUID().toString();

@UpdatePermission(expression = "Principal is Owner AND value is Cancelled")
@CreatePermission(expression = "value is Queued")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

import java.net.URISyntaxException;
import java.util.Date;
import java.util.UUID;
import java.util.concurrent.Callable;

import javax.ws.rs.core.MultivaluedHashMap;
Expand Down Expand Up @@ -70,18 +71,19 @@ public AsyncQueryThread(AsyncQuery queryObj, User user, Elide elide, QueryRunner
* @throws NoHttpResponseException
*/
protected AsyncQueryResult processQuery() throws URISyntaxException, NoHttpResponseException {
UUID requestId = UUID.fromString(queryObj.getRequestId());

ElideResponse response = null;
log.debug("AsyncQuery Object from request: {}", queryObj);
if (queryObj.getQueryType().equals(QueryType.JSONAPI_V1_0)) {
MultivaluedMap<String, String> queryParams = getQueryParams(queryObj.getQuery());
log.debug("Extracted QueryParams from AsyncQuery Object: {}", queryParams);
response = elide.get(getPath(queryObj.getQuery()), queryParams, user, apiVersion);
response = elide.get(getPath(queryObj.getQuery()), queryParams, user, apiVersion, requestId);
log.debug("JSONAPI_V1_0 getResponseCode: {}, JSONAPI_V1_0 getBody: {}",
response.getResponseCode(), response.getBody());
}
else if (queryObj.getQueryType().equals(QueryType.GRAPHQL_V1_0)) {
response = runner.run(queryObj.getQuery(), user);
response = runner.run(queryObj.getQuery(), user, requestId);
log.debug("GRAPHQL_V1_0 getResponseCode: {}, GRAPHQL_V1_0 getBody: {}",
response.getResponseCode(), response.getBody());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import java.io.IOException;
import java.util.Collection;
import java.util.Iterator;
import java.util.UUID;

import javax.inject.Singleton;
import javax.ws.rs.core.MultivaluedHashMap;
Expand Down Expand Up @@ -184,7 +185,7 @@ protected Object executeInTransaction(DataStore dataStore, Transactional action)
JsonApiDocument jsonApiDoc = new JsonApiDocument();
MultivaluedMap<String, String> queryParams = new MultivaluedHashMap<String, String>();
RequestScope scope = new RequestScope("query", NO_VERSION, jsonApiDoc,
tx, null, queryParams, elide.getElideSettings());
tx, null, queryParams, UUID.randomUUID(), elide.getElideSettings());
result = action.execute(tx, scope);
tx.flush(scope);
tx.commit(scope);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ public void testExecuteQueryComplete() throws InterruptedException {
String id = "edc4a871-dff2-4054-804e-d80075cf827d";
when(queryObj.getQuery()).thenReturn(query);
when(queryObj.getId()).thenReturn(id);
when(queryObj.getRequestId()).thenReturn(id);
when(queryObj.getQueryType()).thenReturn(QueryType.JSONAPI_V1_0);
when(queryObj.getAsyncAfterSeconds()).thenReturn(10);
service.executeQuery(queryObj, testUser, NO_VERSION);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

Expand Down Expand Up @@ -52,7 +53,7 @@ public void testProcessQueryJsonApi() throws NoHttpResponseException, URISyntaxE
queryObj.setId(id);
queryObj.setQuery(query);
queryObj.setQueryType(QueryType.JSONAPI_V1_0);
when(elide.get(anyString(), any(), any(), anyString())).thenReturn(response);
when(elide.get(anyString(), any(), any(), anyString(), any())).thenReturn(response);
AsyncQueryThread queryThread = new AsyncQueryThread(queryObj, user, elide, runner, asyncQueryDao, "v1");
queryResultObj = queryThread.processQuery();
assertEquals(queryResultObj.getResponseBody(), "ResponseBody");
Expand All @@ -68,7 +69,7 @@ public void testProcessQueryGraphQl() throws NoHttpResponseException, URISyntaxE
queryObj.setId(id);
queryObj.setQuery(query);
queryObj.setQueryType(QueryType.GRAPHQL_V1_0);
when(runner.run(query, user)).thenReturn(response);
when(runner.run(eq(query), eq(user), any())).thenReturn(response);
AsyncQueryThread queryThread = new AsyncQueryThread(queryObj, user, elide, runner, asyncQueryDao, "v1");
queryResultObj = queryThread.processQuery();
assertEquals(queryResultObj.getResponseBody(), "ResponseBody");
Expand Down
103 changes: 81 additions & 22 deletions elide-core/src/main/java/com/yahoo/elide/Elide.java
Original file line number Diff line number Diff line change
Expand Up @@ -165,16 +165,30 @@ protected Set<Class<?>> registerCustomSerdeScan() {
*/
public ElideResponse get(String path, MultivaluedMap<String, String> queryParams,
User opaqueUser, String apiVersion) {
return handleRequest(true, opaqueUser, dataStore::beginReadTransaction, (tx, user) -> {
return get(path, queryParams, opaqueUser, apiVersion, UUID.randomUUID());
}

/**
* Handle GET.
*
* @param path the path
* @param queryParams the query params
* @param opaqueUser the opaque user
* @param apiVersion the API version
* @param requestId the request ID
* @return Elide response object
*/
public ElideResponse get(String path, MultivaluedMap<String, String> queryParams,
User opaqueUser, String apiVersion, UUID requestId) {
return handleRequest(true, opaqueUser, dataStore::beginReadTransaction, requestId, (tx, user) -> {
JsonApiDocument jsonApiDoc = new JsonApiDocument();
RequestScope requestScope = new RequestScope(path, apiVersion, jsonApiDoc,
tx, user, queryParams, elideSettings);
tx, user, queryParams, requestId, elideSettings);
requestScope.setEntityProjection(new EntityProjectionMaker(elideSettings.getDictionary(),
requestScope).parsePath(path));
BaseVisitor visitor = new GetVisitor(requestScope);
return visit(path, requestScope, visitor);
});

}

/**
Expand All @@ -183,13 +197,28 @@ public ElideResponse get(String path, MultivaluedMap<String, String> queryParams
* @param path the path
* @param jsonApiDocument the json api document
* @param opaqueUser the opaque user
* @param apiVersion the API version
* @return Elide response object
*/
public ElideResponse post(String path, String jsonApiDocument, User opaqueUser, String apiVersion) {
return handleRequest(false, opaqueUser, dataStore::beginTransaction, (tx, user) -> {
return post(path, jsonApiDocument, opaqueUser, apiVersion, UUID.randomUUID());
}

/**
* Handle POST.
*
* @param path the path
* @param jsonApiDocument the json api document
* @param opaqueUser the opaque user
* @param apiVersion the API version
* @param requestId the request ID
* @return Elide response object
*/
public ElideResponse post(String path, String jsonApiDocument, User opaqueUser, String apiVersion, UUID requestId) {
return handleRequest(false, opaqueUser, dataStore::beginTransaction, requestId, (tx, user) -> {
JsonApiDocument jsonApiDoc = mapper.readJsonApiDocument(jsonApiDocument);
RequestScope requestScope = new RequestScope(path, apiVersion,
jsonApiDoc, tx, user, null, elideSettings);
jsonApiDoc, tx, user, null, requestId, elideSettings);
requestScope.setEntityProjection(new EntityProjectionMaker(elideSettings.getDictionary(),
requestScope).parsePath(path));
BaseVisitor visitor = new PostVisitor(requestScope);
Expand All @@ -205,15 +234,36 @@ public ElideResponse post(String path, String jsonApiDocument, User opaqueUser,
* @param path the path
* @param jsonApiDocument the json api document
* @param opaqueUser the opaque user
* @param apiVersion the API version
* @return Elide response object
*/
public ElideResponse patch(String contentType, String accept,
String path, String jsonApiDocument,
User opaqueUser, String apiVersion) {
return patch(contentType, accept, path, jsonApiDocument, opaqueUser, apiVersion, UUID.randomUUID());
}

/**
* Handle PATCH.
*
* @param contentType the content type
* @param accept the accept
* @param path the path
* @param jsonApiDocument the json api document
* @param opaqueUser the opaque user
* @param apiVersion the API version
* @param requestId the request ID
* @return Elide response object
*/
public ElideResponse patch(String contentType, String accept,
String path, String jsonApiDocument, User opaqueUser, String apiVersion) {
String path, String jsonApiDocument,
User opaqueUser, String apiVersion, UUID requestId) {

Handler<DataStoreTransaction, User, HandlerResult> handler;
if (JsonApiPatch.isPatchExtension(contentType) && JsonApiPatch.isPatchExtension(accept)) {
handler = (tx, user) -> {
PatchRequestScope requestScope = new PatchRequestScope(path, apiVersion, tx, user, elideSettings);
PatchRequestScope requestScope = new PatchRequestScope(path, apiVersion, tx,
user, requestId, elideSettings);
try {
Supplier<Pair<Integer, JsonNode>> responder =
JsonApiPatch.processJsonPatch(dataStore, path, jsonApiDocument, requestScope);
Expand All @@ -226,15 +276,29 @@ public ElideResponse patch(String contentType, String accept,
handler = (tx, user) -> {
JsonApiDocument jsonApiDoc = mapper.readJsonApiDocument(jsonApiDocument);
RequestScope requestScope = new RequestScope(path, apiVersion, jsonApiDoc,
tx, user, null, elideSettings);
tx, user, null, requestId, elideSettings);
requestScope.setEntityProjection(new EntityProjectionMaker(elideSettings.getDictionary(),
requestScope).parsePath(path));
BaseVisitor visitor = new PatchVisitor(requestScope);
return visit(path, requestScope, visitor);
};
}

return handleRequest(false, opaqueUser, dataStore::beginTransaction, handler);
return handleRequest(false, opaqueUser, dataStore::beginTransaction, requestId, handler);
}

/**
* Handle DELETE.
*
* @param path the path
* @param jsonApiDocument the json api document
* @param opaqueUser the opaque user
* @param apiVersion the API version
* @return Elide response object
*/
public ElideResponse delete(String path, String jsonApiDocument,
User opaqueUser, String apiVersion) {
return delete(path, jsonApiDocument, opaqueUser, apiVersion, UUID.randomUUID());
}

/**
Expand All @@ -243,15 +307,18 @@ public ElideResponse patch(String contentType, String accept,
* @param path the path
* @param jsonApiDocument the json api document
* @param opaqueUser the opaque user
* @param apiVersion the API version
* @param requestId the request ID
* @return Elide response object
*/
public ElideResponse delete(String path, String jsonApiDocument, User opaqueUser, String apiVersion) {
return handleRequest(false, opaqueUser, dataStore::beginTransaction, (tx, user) -> {
public ElideResponse delete(String path, String jsonApiDocument,
User opaqueUser, String apiVersion, UUID requestId) {
return handleRequest(false, opaqueUser, dataStore::beginTransaction, requestId, (tx, user) -> {
JsonApiDocument jsonApiDoc = StringUtils.isEmpty(jsonApiDocument)
? new JsonApiDocument()
: mapper.readJsonApiDocument(jsonApiDocument);
RequestScope requestScope = new RequestScope(path, apiVersion, jsonApiDoc,
tx, user, null, elideSettings);
tx, user, null, requestId, elideSettings);
requestScope.setEntityProjection(new EntityProjectionMaker(elideSettings.getDictionary(),
requestScope).parsePath(path));
BaseVisitor visitor = new DeleteVisitor(requestScope);
Expand All @@ -274,16 +341,15 @@ public HandlerResult visit(String path, RequestScope requestScope, BaseVisitor v
* @param isReadOnly if the transaction is read only
* @param user the user object from the container
* @param transaction a transaction supplier
* @param requestId the Request ID
* @param handler a function that creates the request scope and request handler
* @return the response
*/
protected ElideResponse handleRequest(boolean isReadOnly, User user,
Supplier<DataStoreTransaction> transaction,
Supplier<DataStoreTransaction> transaction, UUID requestId,
Handler<DataStoreTransaction, User, HandlerResult> handler) {
boolean isVerbose = false;
UUID requestId = null;
try (DataStoreTransaction tx = transaction.get()) {
requestId = tx.getRequestId();
transactionRegistry.addRunningTransaction(requestId, tx);
HandlerResult result = handler.handle(tx, user);
RequestScope requestScope = result.getRequestScope();
Expand Down Expand Up @@ -313,29 +379,23 @@ protected ElideResponse handleRequest(boolean isReadOnly, User user,

} catch (WebApplicationException e) {
throw e;

} catch (ForbiddenAccessException e) {
if (log.isDebugEnabled()) {
log.debug("{}", e.getLoggedMessage());
}
return buildErrorResponse(e, isVerbose);

} catch (JsonPatchExtensionException e) {
log.debug("JSON patch extension exception caught", e);
return buildErrorResponse(e, isVerbose);

} catch (HttpStatusException e) {
log.debug("Caught HTTP status exception", e);
return buildErrorResponse(e, isVerbose);

} catch (IOException e) {
log.error("IO Exception uncaught by Elide", e);
return buildErrorResponse(new TransactionException(e), isVerbose);

} catch (ParseCancellationException e) {
log.debug("Parse cancellation exception uncaught by Elide (i.e. invalid URL)", e);
return buildErrorResponse(new InvalidURLException(e), isVerbose);

} catch (ConstraintViolationException e) {
log.debug("Constraint violation exception caught", e);
String message = "Constraint violation";
Expand All @@ -351,7 +411,6 @@ protected ElideResponse handleRequest(boolean isReadOnly, User user,
}
log.error("Error or exception uncaught by Elide", e);
throw e;

} finally {
transactionRegistry.removeRunningTransaction(requestId);
auditLogger.clear();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
import java.io.Serializable;
import java.util.Iterator;
import java.util.Set;
import java.util.UUID;
/**
* Wraps the Database Transaction type.
*/
Expand Down Expand Up @@ -262,11 +261,6 @@ default boolean supportsSorting(Class<?> entityClass, Sorting sorting) {
default boolean supportsPagination(Class<?> entityClass, FilterExpression expression) {
return true;
}
/**
* Transaction ID for each transaction
* @return UUID id
*/
UUID getRequestId();

/**
* Cancel running transaction.
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public class RequestScope implements com.yahoo.elide.security.RequestScope {

//TODO - this ought to be read only and set in the constructor.
@Getter @Setter private EntityProjection entityProjection;
private final String requestId;
private final UUID requestId;
private final Map<String, FilterExpression> expressionsByType;

private PublishSubject<CRUDEvent> lifecycleEvents;
Expand All @@ -94,6 +94,7 @@ public RequestScope(String path,
DataStoreTransaction transaction,
User user,
MultivaluedMap<String, String> queryParams,
UUID requestId,
ElideSettings elideSettings) {
this.apiVersion = apiVersion;
this.lifecycleEvents = PublishSubject.create();
Expand All @@ -119,7 +120,7 @@ public RequestScope(String path,
this.newPersistentResources = new LinkedHashSet<>();
this.dirtyResources = new LinkedHashSet<>();
this.deletedResources = new LinkedHashSet<>();
this.requestId = UUID.randomUUID().toString();
this.requestId = requestId;

Function<RequestScope, PermissionExecutor> permissionExecutorGenerator = elideSettings.getPermissionExecutor();
this.permissionExecutor = (permissionExecutorGenerator == null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
package com.yahoo.elide.core.datastore.inmemory;

import com.yahoo.elide.core.DataStoreTransaction;
import com.yahoo.elide.core.DataStoreTransactionImplementation;
import com.yahoo.elide.core.EntityDictionary;
import com.yahoo.elide.core.RequestScope;
import com.yahoo.elide.core.exceptions.TransactionException;
Expand All @@ -28,7 +27,7 @@
/**
* HashMapDataStore transaction handler.
*/
public class HashMapStoreTransaction extends DataStoreTransactionImplementation {
public class HashMapStoreTransaction implements DataStoreTransaction {
private final Map<Class<?>, Map<String, Object>> dataStore;
private final List<Operation> operations;
private final EntityDictionary dictionary;
Expand Down
Loading

0 comments on commit 70ab71e

Please sign in to comment.