Skip to content

Commit

Permalink
Adding support for populating Meta object in JSON-API (#2824)
Browse files Browse the repository at this point in the history
* Adding support for populating Meta object in JSON-API

* Added WithMeatadata interface

* Fixed checkstyle

* Removed unnecessary interface prototypes in RequestScope

* Added unit test.

* Added IT test for in memory store for metadata JSON-API

* Added IT test.

* Fixed checkstyles and NPE

* Moved logic to add resource meta to persistentResource.toMeta

* Fixed checkstyles and added one more UT

* Another checkstyle error

* Inspection rework
  • Loading branch information
aklish committed Nov 8, 2022
1 parent 61fab94 commit 86203f0
Show file tree
Hide file tree
Showing 18 changed files with 464 additions and 42 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,9 @@
import com.yahoo.elide.core.type.ClassType;
import com.yahoo.elide.core.type.Type;
import com.yahoo.elide.core.utils.coerce.CoerceUtil;
import com.yahoo.elide.jsonapi.document.processors.WithMetadata;
import com.yahoo.elide.jsonapi.models.Data;
import com.yahoo.elide.jsonapi.models.Meta;
import com.yahoo.elide.jsonapi.models.Relationship;
import com.yahoo.elide.jsonapi.models.Resource;
import com.yahoo.elide.jsonapi.models.ResourceIdentifier;
Expand All @@ -71,6 +73,7 @@
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
Expand Down Expand Up @@ -1553,6 +1556,26 @@ public Resource toResource(final Map<String, Relationship> relationships,
if (requestScope.getElideSettings().isEnableJsonLinks()) {
resource.setLinks(requestScope.getElideSettings().getJsonApiLinks().getResourceLevelLinks(this));
}

if (! (getObject() instanceof WithMetadata)) {
return resource;
}

WithMetadata withMetadata = (WithMetadata) getObject();
Set<String> fields = withMetadata.getMetadataFields();

if (fields.size() == 0) {
return resource;
}

Meta meta = new Meta(new HashMap<>());

for (String field : fields) {
meta.getMetaMap().put(field, withMetadata.getMetadataField(field).get());
}

resource.setMeta(meta);

return resource;
}

Expand Down
19 changes: 19 additions & 0 deletions elide-core/src/main/java/com/yahoo/elide/core/RequestScope.java
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ public class RequestScope implements com.yahoo.elide.core.security.RequestScope
@Getter private final UUID requestId;
private final Map<String, FilterExpression> expressionsByType;

private final Map<String, Object> metadata;

private LinkedHashSet<CRUDEvent> eventQueue;

/* Used to filter across heterogeneous types during the first load */
Expand Down Expand Up @@ -125,6 +127,7 @@ public RequestScope(String baseUrlEndPoint,
this.dirtyResources = new LinkedHashSet<>();
this.deletedResources = new LinkedHashSet<>();
this.requestId = requestId;
this.metadata = new HashMap<>();
this.queryParams = queryParams == null ? new MultivaluedHashMap<>() : queryParams;

this.requestHeaders = MapUtils.isEmpty(requestHeaders)
Expand Down Expand Up @@ -214,6 +217,7 @@ protected RequestScope(String path, String apiVersion,
this.updateStatusCode = outerRequestScope.updateStatusCode;
this.requestId = outerRequestScope.requestId;
this.sparseFields = outerRequestScope.sparseFields;
this.metadata = new HashMap<>(outerRequestScope.metadata);
}

public Set<com.yahoo.elide.core.security.PersistentResource> getNewResources() {
Expand Down Expand Up @@ -464,4 +468,19 @@ public String getRequestHeaderByName(String headerName) {
}
return this.requestHeaders.get(headerName).get(0);
}

@Override
public void setMetadataField(String property, Object value) {
metadata.put(property, value);
}

@Override
public Optional<Object> getMetadataField(String property) {
return Optional.ofNullable(metadata.getOrDefault(property, null));
}

@Override
public Set<String> getMetadataFields() {
return metadata.keySet();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@
package com.yahoo.elide.core.security;

import com.yahoo.elide.core.datastore.DataStoreTransaction;
import com.yahoo.elide.jsonapi.document.processors.WithMetadata;

import java.util.List;
import java.util.Map;

/**
* The request scope interface passed to checks.
*/
public interface RequestScope {
public interface RequestScope extends WithMetadata {
User getUser();
String getApiVersion();
String getRequestHeaderByName(String headerName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@
package com.yahoo.elide.jsonapi.document.processors;

import com.yahoo.elide.core.PersistentResource;
import com.yahoo.elide.core.RequestScope;
import com.yahoo.elide.jsonapi.models.JsonApiDocument;

import java.util.Set;
import java.util.LinkedHashSet;
import javax.ws.rs.core.MultivaluedMap;

/**
Expand All @@ -22,20 +23,26 @@ public interface DocumentProcessor {
* A method for making transformations to the JsonApiDocument.
*
* @param jsonApiDocument the json api document
* @param scope the request scope
* @param resource the resource
* @param queryParams the query params
*/
void execute(JsonApiDocument jsonApiDocument, PersistentResource resource,
void execute(JsonApiDocument jsonApiDocument,
RequestScope scope,
PersistentResource resource,
MultivaluedMap<String, String> queryParams);

/**
* A method for making transformations to the JsonApiDocument.
*
* @param jsonApiDocument the json api document
* @param scope the request scope
* @param resources the resources
* @param queryParams the query params
*/
void execute(JsonApiDocument jsonApiDocument, Set<PersistentResource> resources,
void execute(JsonApiDocument jsonApiDocument,
RequestScope scope,
LinkedHashSet<PersistentResource> resources,
MultivaluedMap<String, String> queryParams);

//TODO Possibly add a something like a 'afterExecute' method to process after the first round of execution
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
package com.yahoo.elide.jsonapi.document.processors;

import com.yahoo.elide.core.PersistentResource;
import com.yahoo.elide.core.RequestScope;
import com.yahoo.elide.core.exceptions.ForbiddenAccessException;
import com.yahoo.elide.core.request.EntityProjection;
import com.yahoo.elide.core.request.Relationship;
Expand Down Expand Up @@ -33,7 +34,7 @@ public class IncludedProcessor implements DocumentProcessor {
* to the included block of the JsonApiDocument.
*/
@Override
public void execute(JsonApiDocument jsonApiDocument, PersistentResource resource,
public void execute(JsonApiDocument jsonApiDocument, RequestScope scope, PersistentResource resource,
MultivaluedMap<String, String> queryParams) {
if (isPresent(queryParams, INCLUDE)) {
addIncludedResources(jsonApiDocument, resource, queryParams.get(INCLUDE));
Expand All @@ -45,8 +46,12 @@ public void execute(JsonApiDocument jsonApiDocument, PersistentResource resource
* to the included block of the JsonApiDocument.
*/
@Override
public void execute(JsonApiDocument jsonApiDocument, Set<PersistentResource> resources,
MultivaluedMap<String, String> queryParams) {
public void execute(
JsonApiDocument jsonApiDocument,
RequestScope scope,
LinkedHashSet<PersistentResource> resources,
MultivaluedMap<String, String> queryParams
) {
if (isPresent(queryParams, INCLUDE)) {

// Process include for each resource
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright 2022, Yahoo Inc.
* Licensed under the Apache License, Version 2.0
* See LICENSE file in project root for terms.
*/

package com.yahoo.elide.jsonapi.document.processors;

import com.yahoo.elide.core.PersistentResource;
import com.yahoo.elide.core.RequestScope;
import com.yahoo.elide.jsonapi.models.JsonApiDocument;
import com.yahoo.elide.jsonapi.models.Meta;

import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Set;
import javax.ws.rs.core.MultivaluedMap;

/**
* Document processor that populates 'meta' fields for collections (from request scope metadata) and
* resources (from resource metadata). This processor runs after the document has already been populated.
*/
public class PopulateMetaProcessor implements DocumentProcessor {
@Override
public void execute(
JsonApiDocument jsonApiDocument,
RequestScope scope,
PersistentResource persistentResource,
MultivaluedMap<String, String> queryParams
) {

addDocumentMeta(jsonApiDocument, scope);
}

private void addDocumentMeta(JsonApiDocument document, RequestScope scope) {
Set<String> fields = scope.getMetadataFields();
if (fields.size() == 0) {
return;
}
Meta meta = document.getMeta();
if (meta == null) {
meta = new Meta(new HashMap<>());
}

for (String field : fields) {
meta.getMetaMap().put(field, scope.getMetadataField(field).get());
}

document.setMeta(meta);
}

@Override
public void execute(
JsonApiDocument jsonApiDocument,
RequestScope scope,
LinkedHashSet<PersistentResource> resources,
MultivaluedMap<String, String> queryParams
) {
addDocumentMeta(jsonApiDocument, scope);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright 2022, Yahoo Inc.
* Licensed under the Apache License, Version 2.0
* See LICENSE file in project root for terms.
*/

package com.yahoo.elide.jsonapi.document.processors;

import java.util.Optional;
import java.util.Set;

/**
* The class carries metadata fields.
*/
public interface WithMetadata {

/**
* Sets a metadata property for this request.
* @param property
* @param value
*/
default void setMetadataField(String property, Object value) {
//noop
}

/**
* Retrieves a metadata property from this request.
* @param property
* @return An optional metadata property.
*/
Optional<Object> getMetadataField(String property);

/**
* Return the set of metadata fields that have been set.
* @return metadata fields that have been set.
*/
Set<String> getMetadataFields();
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public class Resource {
private Map<String, Object> attributes;
private Map<String, Relationship> relationships;
private Map<String, String> links;
private Map<String, Meta> meta;
private Meta meta;

public Resource(String type, String id) {
this.type = type;
Expand All @@ -56,7 +56,7 @@ public Resource(@JsonProperty("type") String type,
@JsonProperty("attributes") Map<String, Object> attributes,
@JsonProperty("relationships") Map<String, Relationship> relationships,
@JsonProperty("links") Map<String, String> links,
@JsonProperty("meta") Map<String, Meta> meta) {
@JsonProperty("meta") Meta meta) {
this.type = type;
this.id = id;
this.attributes = attributes;
Expand Down Expand Up @@ -101,11 +101,11 @@ public String getType() {
}

@JsonInclude(JsonInclude.Include.NON_NULL)
public Map<String, Meta> getMeta() {
public Meta getMeta() {
return meta;
}

public void setMeta(Map<String, Meta> meta) {
public void setMeta(Meta meta) {
this.meta = meta;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import com.yahoo.elide.generated.parsers.CoreParser.SubCollectionSubCollectionContext;
import com.yahoo.elide.jsonapi.document.processors.DocumentProcessor;
import com.yahoo.elide.jsonapi.document.processors.IncludedProcessor;
import com.yahoo.elide.jsonapi.document.processors.PopulateMetaProcessor;
import com.yahoo.elide.jsonapi.models.Data;
import com.yahoo.elide.jsonapi.models.JsonApiDocument;
import com.yahoo.elide.jsonapi.models.Resource;
Expand Down Expand Up @@ -186,7 +187,10 @@ protected static JsonApiDocument getResponseBody(PersistentResource resource, Re

//TODO Iterate over set of document processors
DocumentProcessor includedProcessor = new IncludedProcessor();
includedProcessor.execute(jsonApiDocument, resource, queryParams);
includedProcessor.execute(jsonApiDocument, requestScope, resource, queryParams);

PopulateMetaProcessor metaProcessor = new PopulateMetaProcessor();
metaProcessor.execute(jsonApiDocument, requestScope, resource, queryParams);

return jsonApiDocument;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import com.yahoo.elide.jsonapi.JsonApiMapper;
import com.yahoo.elide.jsonapi.document.processors.DocumentProcessor;
import com.yahoo.elide.jsonapi.document.processors.IncludedProcessor;
import com.yahoo.elide.jsonapi.document.processors.PopulateMetaProcessor;
import com.yahoo.elide.jsonapi.models.Data;
import com.yahoo.elide.jsonapi.models.JsonApiDocument;
import com.yahoo.elide.jsonapi.models.Meta;
Expand Down Expand Up @@ -71,15 +72,15 @@ public Supplier<Pair<Integer, JsonApiDocument>> handleGet(StateContext state) {
RequestScope requestScope = state.getRequestScope();
MultivaluedMap<String, String> queryParams = requestScope.getQueryParams();

Set<PersistentResource> collection =
LinkedHashSet<PersistentResource> collection =
getResourceCollection(requestScope).toList(LinkedHashSet::new).blockingGet();

// Set data
jsonApiDocument.setData(getData(collection, requestScope.getDictionary()));

// Run include processor
DocumentProcessor includedProcessor = new IncludedProcessor();
includedProcessor.execute(jsonApiDocument, collection, queryParams);
includedProcessor.execute(jsonApiDocument, requestScope, collection, queryParams);

Pagination pagination = parentProjection.getPagination();
if (parent.isPresent()) {
Expand Down Expand Up @@ -109,6 +110,9 @@ public Supplier<Pair<Integer, JsonApiDocument>> handleGet(StateContext state) {
jsonApiDocument.setMeta(meta);
}

PopulateMetaProcessor metaProcessor = new PopulateMetaProcessor();
metaProcessor.execute(jsonApiDocument, requestScope, collection, queryParams);

return () -> Pair.of(HttpStatus.SC_OK, jsonApiDocument);
}

Expand All @@ -122,6 +126,10 @@ public Supplier<Pair<Integer, JsonApiDocument>> handlePost(StateContext state) {
return () -> {
JsonApiDocument returnDoc = new JsonApiDocument();
returnDoc.setData(new Data<>(newObject.toResource()));

PopulateMetaProcessor metaProcessor = new PopulateMetaProcessor();
metaProcessor.execute(returnDoc, requestScope, newObject, requestScope.getQueryParams());

return Pair.of(HttpStatus.SC_CREATED, returnDoc);
};
}
Expand Down
Loading

0 comments on commit 86203f0

Please sign in to comment.