Search in sources :

Example 16 with Relationship

use of com.yahoo.elide.jsonapi.models.Relationship in project elide by yahoo.

the class PersistentResourceTest method testTransferPermissionSuccessOnUpdateSingularRelationship.

@Test
public void testTransferPermissionSuccessOnUpdateSingularRelationship() {
    example.User userModel = new example.User();
    userModel.setId(1);
    NoShareEntity noShare = new NoShareEntity();
    /* The noshare already exists so no exception should be thrown */
    userModel.setNoShare(noShare);
    List<Resource> idList = new ArrayList<>();
    idList.add(new ResourceIdentifier("noshare", "1").castToResource());
    Relationship ids = new Relationship(null, new Data<>(idList));
    when(tx.getToOneRelation(any(), eq(userModel), any(), any())).thenReturn(noShare);
    when(tx.loadObject(any(), eq(1L), any())).thenReturn(noShare);
    RequestScope goodScope = buildRequestScope(tx, goodUser);
    PersistentResource<example.User> userResource = new PersistentResource<>(userModel, goodScope.getUUIDFor(userModel), goodScope);
    boolean returnVal = userResource.updateRelation("noShare", ids.toPersistentResources(goodScope));
    assertFalse(returnVal);
    assertEquals(noShare, userModel.getNoShare());
}
Also used : TestUser(com.yahoo.elide.core.security.TestUser) User(com.yahoo.elide.core.security.User) Resource(com.yahoo.elide.jsonapi.models.Resource) ArrayList(java.util.ArrayList) PatchRequestScope(com.yahoo.elide.jsonapi.extensions.PatchRequestScope) ResourceIdentifier(com.yahoo.elide.jsonapi.models.ResourceIdentifier) Relationship(com.yahoo.elide.jsonapi.models.Relationship) NoShareEntity(example.NoShareEntity) Test(org.junit.jupiter.api.Test)

Example 17 with Relationship

use of com.yahoo.elide.jsonapi.models.Relationship in project elide by yahoo.

the class PersistentResource method getRelation.

/**
 * Load a relation from the PersistentResource.
 *
 * @param relationship the relation
 * @param ids          a list of object identifiers to optionally load.  Can be empty.
 * @return PersistentResource relation
 */
public Observable<PersistentResource> getRelation(List<String> ids, com.yahoo.elide.core.request.Relationship relationship) {
    FilterExpression filterExpression = Optional.ofNullable(relationship.getProjection().getFilterExpression()).orElse(null);
    assertPropertyExists(relationship.getName());
    Type<?> entityType = dictionary.getParameterizedType(getResourceType(), relationship.getName());
    Set<PersistentResource> newResources = new LinkedHashSet<>();
    /* If this is a bulk edit request and the ID we are fetching for is newly created... */
    if (!ids.isEmpty()) {
        // Fetch our set of new resources that we know about since we can't find them in the datastore
        newResources = requestScope.getNewPersistentResources().stream().filter(resource -> entityType.isAssignableFrom(resource.getResourceType()) && ids.contains(resource.getUUID().orElse(""))).collect(Collectors.toSet());
        FilterExpression idExpression = buildIdFilterExpression(ids, entityType, dictionary, requestScope);
        // Combine filters if necessary
        filterExpression = Optional.ofNullable(relationship.getProjection().getFilterExpression()).map(fe -> (FilterExpression) new AndFilterExpression(idExpression, fe)).orElse(idExpression);
    }
    // TODO: Filter on new resources?
    // TODO: Update pagination to subtract the number of new resources created?
    Observable<PersistentResource> existingResources = filter(ReadPermission.class, Optional.ofNullable(filterExpression), relationship.getProjection().getRequestedFields(), getRelation(relationship.copyOf().projection(relationship.getProjection().copyOf().filterExpression(filterExpression).build()).build(), true));
    // TODO: Sort again in memory now that two sets are glommed together?
    Observable<PersistentResource> allResources = Observable.fromIterable(newResources).mergeWith(existingResources);
    Set<String> foundIds = new HashSet<>();
    allResources = allResources.doOnNext((resource) -> {
        String id = (String) (resource.getUUID().orElseGet(resource::getId));
        if (ids.contains(id)) {
            foundIds.add(id);
        }
    });
    allResources = allResources.doOnComplete(() -> {
        Set<String> missedIds = Sets.difference(new HashSet<>(ids), foundIds);
        if (!missedIds.isEmpty()) {
            throw new InvalidObjectIdentifierException(missedIds.toString(), relationship.getName());
        }
    });
    return allResources;
}
Also used : LinkedHashSet(java.util.LinkedHashSet) Resource(com.yahoo.elide.jsonapi.models.Resource) Data(com.yahoo.elide.jsonapi.models.Data) StringUtils(org.apache.commons.lang3.StringUtils) UpdatePermission(com.yahoo.elide.annotation.UpdatePermission) ClassType(com.yahoo.elide.core.type.ClassType) DeletePermission(com.yahoo.elide.annotation.DeletePermission) Argument(com.yahoo.elide.core.request.Argument) InvalidSyntaxException(com.yahoo.elide.core.audit.InvalidSyntaxException) Map(java.util.Map) DataStoreIterable(com.yahoo.elide.core.datastore.DataStoreIterable) LifeCycleHookBinding(com.yahoo.elide.annotation.LifeCycleHookBinding) EntityBinding(com.yahoo.elide.core.dictionary.EntityBinding) NonNull(lombok.NonNull) Collection(java.util.Collection) Set(java.util.Set) CoerceUtil(com.yahoo.elide.core.utils.coerce.CoerceUtil) Collectors(java.util.stream.Collectors) EntityDictionary(com.yahoo.elide.core.dictionary.EntityDictionary) Sets(com.google.common.collect.Sets) Serializable(java.io.Serializable) Objects(java.util.Objects) ExpressionResult(com.yahoo.elide.core.security.permissions.ExpressionResult) List(java.util.List) Annotation(java.lang.annotation.Annotation) AndFilterExpression(com.yahoo.elide.core.filter.expression.AndFilterExpression) Optional(java.util.Optional) RelationshipType(com.yahoo.elide.core.dictionary.RelationshipType) Attribute(com.yahoo.elide.core.request.Attribute) InvalidAttributeException(com.yahoo.elide.core.exceptions.InvalidAttributeException) Function(java.util.function.Function) Supplier(java.util.function.Supplier) CollectionUtils(org.apache.commons.collections4.CollectionUtils) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) LinkedHashMap(java.util.LinkedHashMap) IterableUtils(org.apache.commons.collections4.IterableUtils) LogMessageImpl(com.yahoo.elide.core.audit.LogMessageImpl) DELETE(com.yahoo.elide.annotation.LifeCycleHookBinding.Operation.DELETE) EntityDictionary.getType(com.yahoo.elide.core.dictionary.EntityDictionary.getType) JsonIgnore(com.fasterxml.jackson.annotation.JsonIgnore) Predicates(com.google.common.base.Predicates) InternalServerErrorException(com.yahoo.elide.core.exceptions.InternalServerErrorException) CanPaginateVisitor(com.yahoo.elide.core.security.visitors.CanPaginateVisitor) Observable(io.reactivex.Observable) LogMessage(com.yahoo.elide.core.audit.LogMessage) FilterExpression(com.yahoo.elide.core.filter.expression.FilterExpression) LinkedHashSet(java.util.LinkedHashSet) UPDATE(com.yahoo.elide.annotation.LifeCycleHookBinding.Operation.UPDATE) DataStoreTransaction(com.yahoo.elide.core.datastore.DataStoreTransaction) VerifyFieldAccessFilterExpressionVisitor(com.yahoo.elide.core.filter.visitors.VerifyFieldAccessFilterExpressionVisitor) ChangeSpec(com.yahoo.elide.core.security.ChangeSpec) COLLECTION_TYPE(com.yahoo.elide.core.type.ClassType.COLLECTION_TYPE) Sorting(com.yahoo.elide.core.request.Sorting) InvalidEntityBodyException(com.yahoo.elide.core.exceptions.InvalidEntityBodyException) InvalidObjectIdentifierException(com.yahoo.elide.core.exceptions.InvalidObjectIdentifierException) InPredicate(com.yahoo.elide.core.filter.predicates.InPredicate) EntityProjection(com.yahoo.elide.core.request.EntityProjection) Relationship(com.yahoo.elide.jsonapi.models.Relationship) ForbiddenAccessException(com.yahoo.elide.core.exceptions.ForbiddenAccessException) ReadPermission(com.yahoo.elide.annotation.ReadPermission) BadRequestException(com.yahoo.elide.core.exceptions.BadRequestException) Pagination(com.yahoo.elide.core.request.Pagination) ResourceIdentifier(com.yahoo.elide.jsonapi.models.ResourceIdentifier) TreeMap(java.util.TreeMap) CreatePermission(com.yahoo.elide.annotation.CreatePermission) CREATE(com.yahoo.elide.annotation.LifeCycleHookBinding.Operation.CREATE) Type(com.yahoo.elide.core.type.Type) Preconditions(com.google.common.base.Preconditions) Comparator(java.util.Comparator) Collections(java.util.Collections) EMPTY_BINDING(com.yahoo.elide.core.dictionary.EntityBinding.EMPTY_BINDING) Audit(com.yahoo.elide.annotation.Audit) NonTransferable(com.yahoo.elide.annotation.NonTransferable) Set(java.util.Set) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet) InvalidObjectIdentifierException(com.yahoo.elide.core.exceptions.InvalidObjectIdentifierException) AndFilterExpression(com.yahoo.elide.core.filter.expression.AndFilterExpression) FilterExpression(com.yahoo.elide.core.filter.expression.FilterExpression) AndFilterExpression(com.yahoo.elide.core.filter.expression.AndFilterExpression) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet)

Example 18 with Relationship

use of com.yahoo.elide.jsonapi.models.Relationship in project elide by yahoo.

the class PersistentResource method createObject.

/**
 * Create a resource in the database.
 *
 * @param parent             - The immediate ancestor in the lineage or null if this is a root.
 * @param parentRelationship - The name of the parent relationship traversed to create this object.
 * @param entityClass        the entity class
 * @param requestScope       the request scope
 * @param uuid               the (optional) uuid
 * @param <T>                object type
 * @return persistent resource
 */
public static <T> PersistentResource<T> createObject(PersistentResource<?> parent, String parentRelationship, Type<T> entityClass, RequestScope requestScope, Optional<String> uuid) {
    T obj = requestScope.getTransaction().createNewObject(entityClass, requestScope);
    String id = uuid.orElse(null);
    PersistentResource<T> newResource = new PersistentResource<>(obj, parent, parentRelationship, id, requestScope);
    // The ID must be assigned before we add it to the new resources set.  Persistent resource
    // hashcode and equals are only based on the ID/UUID & type.
    assignId(newResource, id);
    // Keep track of new resources for non-transferable resources
    requestScope.getNewPersistentResources().add(newResource);
    checkPermission(CreatePermission.class, newResource);
    newResource.auditClass(Audit.Action.CREATE, new ChangeSpec(newResource, null, null, newResource.getObject()));
    requestScope.publishLifecycleEvent(newResource, CREATE);
    requestScope.setUUIDForObject(newResource.type, id, newResource.getObject());
    // Initialize null ToMany collections
    requestScope.getDictionary().getRelationships(entityClass).stream().filter(relationName -> newResource.getRelationshipType(relationName).isToMany() && newResource.getValueUnchecked(relationName) == null).forEach(relationName -> newResource.setValue(relationName, new LinkedHashSet<>()));
    newResource.markDirty();
    return newResource;
}
Also used : Resource(com.yahoo.elide.jsonapi.models.Resource) Data(com.yahoo.elide.jsonapi.models.Data) StringUtils(org.apache.commons.lang3.StringUtils) UpdatePermission(com.yahoo.elide.annotation.UpdatePermission) ClassType(com.yahoo.elide.core.type.ClassType) DeletePermission(com.yahoo.elide.annotation.DeletePermission) Argument(com.yahoo.elide.core.request.Argument) InvalidSyntaxException(com.yahoo.elide.core.audit.InvalidSyntaxException) Map(java.util.Map) DataStoreIterable(com.yahoo.elide.core.datastore.DataStoreIterable) LifeCycleHookBinding(com.yahoo.elide.annotation.LifeCycleHookBinding) EntityBinding(com.yahoo.elide.core.dictionary.EntityBinding) NonNull(lombok.NonNull) Collection(java.util.Collection) Set(java.util.Set) CoerceUtil(com.yahoo.elide.core.utils.coerce.CoerceUtil) Collectors(java.util.stream.Collectors) EntityDictionary(com.yahoo.elide.core.dictionary.EntityDictionary) Sets(com.google.common.collect.Sets) Serializable(java.io.Serializable) Objects(java.util.Objects) ExpressionResult(com.yahoo.elide.core.security.permissions.ExpressionResult) List(java.util.List) Annotation(java.lang.annotation.Annotation) AndFilterExpression(com.yahoo.elide.core.filter.expression.AndFilterExpression) Optional(java.util.Optional) RelationshipType(com.yahoo.elide.core.dictionary.RelationshipType) Attribute(com.yahoo.elide.core.request.Attribute) InvalidAttributeException(com.yahoo.elide.core.exceptions.InvalidAttributeException) Function(java.util.function.Function) Supplier(java.util.function.Supplier) CollectionUtils(org.apache.commons.collections4.CollectionUtils) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) LinkedHashMap(java.util.LinkedHashMap) IterableUtils(org.apache.commons.collections4.IterableUtils) LogMessageImpl(com.yahoo.elide.core.audit.LogMessageImpl) DELETE(com.yahoo.elide.annotation.LifeCycleHookBinding.Operation.DELETE) EntityDictionary.getType(com.yahoo.elide.core.dictionary.EntityDictionary.getType) JsonIgnore(com.fasterxml.jackson.annotation.JsonIgnore) Predicates(com.google.common.base.Predicates) InternalServerErrorException(com.yahoo.elide.core.exceptions.InternalServerErrorException) CanPaginateVisitor(com.yahoo.elide.core.security.visitors.CanPaginateVisitor) Observable(io.reactivex.Observable) LogMessage(com.yahoo.elide.core.audit.LogMessage) FilterExpression(com.yahoo.elide.core.filter.expression.FilterExpression) LinkedHashSet(java.util.LinkedHashSet) UPDATE(com.yahoo.elide.annotation.LifeCycleHookBinding.Operation.UPDATE) DataStoreTransaction(com.yahoo.elide.core.datastore.DataStoreTransaction) VerifyFieldAccessFilterExpressionVisitor(com.yahoo.elide.core.filter.visitors.VerifyFieldAccessFilterExpressionVisitor) ChangeSpec(com.yahoo.elide.core.security.ChangeSpec) COLLECTION_TYPE(com.yahoo.elide.core.type.ClassType.COLLECTION_TYPE) Sorting(com.yahoo.elide.core.request.Sorting) InvalidEntityBodyException(com.yahoo.elide.core.exceptions.InvalidEntityBodyException) InvalidObjectIdentifierException(com.yahoo.elide.core.exceptions.InvalidObjectIdentifierException) InPredicate(com.yahoo.elide.core.filter.predicates.InPredicate) EntityProjection(com.yahoo.elide.core.request.EntityProjection) Relationship(com.yahoo.elide.jsonapi.models.Relationship) ForbiddenAccessException(com.yahoo.elide.core.exceptions.ForbiddenAccessException) ReadPermission(com.yahoo.elide.annotation.ReadPermission) BadRequestException(com.yahoo.elide.core.exceptions.BadRequestException) Pagination(com.yahoo.elide.core.request.Pagination) ResourceIdentifier(com.yahoo.elide.jsonapi.models.ResourceIdentifier) TreeMap(java.util.TreeMap) CreatePermission(com.yahoo.elide.annotation.CreatePermission) CREATE(com.yahoo.elide.annotation.LifeCycleHookBinding.Operation.CREATE) Type(com.yahoo.elide.core.type.Type) Preconditions(com.google.common.base.Preconditions) Comparator(java.util.Comparator) Collections(java.util.Collections) EMPTY_BINDING(com.yahoo.elide.core.dictionary.EntityBinding.EMPTY_BINDING) Audit(com.yahoo.elide.annotation.Audit) NonTransferable(com.yahoo.elide.annotation.NonTransferable) LinkedHashSet(java.util.LinkedHashSet) ChangeSpec(com.yahoo.elide.core.security.ChangeSpec)

Example 19 with Relationship

use of com.yahoo.elide.jsonapi.models.Relationship in project elide by yahoo.

the class CollectionTerminalState method createObject.

private PersistentResource createObject(RequestScope requestScope) throws ForbiddenAccessException, InvalidObjectIdentifierException {
    JsonApiDocument doc = requestScope.getJsonApiDocument();
    JsonApiMapper mapper = requestScope.getMapper();
    if (doc.getData() == null) {
        throw new InvalidEntityBodyException("Invalid JSON-API document: " + doc);
    }
    Data<Resource> data = doc.getData();
    Collection<Resource> resources = data.get();
    Resource resource = (resources.size() == 1) ? IterableUtils.first(resources) : null;
    if (resource == null) {
        try {
            throw new InvalidEntityBodyException(mapper.writeJsonApiDocument(doc));
        } catch (JsonProcessingException e) {
            throw new InternalServerErrorException(e);
        }
    }
    String id = resource.getId();
    Type<?> newObjectClass = requestScope.getDictionary().getEntityClass(resource.getType(), requestScope.getApiVersion());
    if (newObjectClass == null) {
        throw new UnknownEntityException("Entity " + resource.getType() + " not found");
    }
    if (!entityClass.isAssignableFrom(newObjectClass)) {
        throw new InvalidValueException("Cannot assign value of type: " + resource.getType() + " to type: " + entityClass);
    }
    PersistentResource pResource = PersistentResource.createObject(parent.orElse(null), relationName.orElse(null), newObjectClass, requestScope, Optional.ofNullable(id));
    Map<String, Object> attributes = resource.getAttributes();
    if (attributes != null) {
        for (Map.Entry<String, Object> entry : attributes.entrySet()) {
            String fieldName = entry.getKey();
            Object val = entry.getValue();
            pResource.updateAttribute(fieldName, val);
        }
    }
    Map<String, Relationship> relationships = resource.getRelationships();
    if (relationships != null) {
        for (Map.Entry<String, Relationship> entry : relationships.entrySet()) {
            String fieldName = entry.getKey();
            Relationship relationship = entry.getValue();
            Set<PersistentResource> resourceSet = (relationship == null) ? null : relationship.toPersistentResources(requestScope);
            pResource.updateRelation(fieldName, resourceSet);
        }
    }
    return pResource;
}
Also used : PersistentResource(com.yahoo.elide.core.PersistentResource) JsonApiDocument(com.yahoo.elide.jsonapi.models.JsonApiDocument) UnknownEntityException(com.yahoo.elide.core.exceptions.UnknownEntityException) Resource(com.yahoo.elide.jsonapi.models.Resource) PersistentResource(com.yahoo.elide.core.PersistentResource) ToString(lombok.ToString) InvalidValueException(com.yahoo.elide.core.exceptions.InvalidValueException) InvalidEntityBodyException(com.yahoo.elide.core.exceptions.InvalidEntityBodyException) Relationship(com.yahoo.elide.jsonapi.models.Relationship) InternalServerErrorException(com.yahoo.elide.core.exceptions.InternalServerErrorException) JsonApiMapper(com.yahoo.elide.jsonapi.JsonApiMapper) JsonProcessingException(com.fasterxml.jackson.core.JsonProcessingException) HashMap(java.util.HashMap) Map(java.util.Map) MultivaluedMap(javax.ws.rs.core.MultivaluedMap)

Example 20 with Relationship

use of com.yahoo.elide.jsonapi.models.Relationship in project elide by yahoo.

the class RelationshipTerminalState method handleGet.

@Override
public Supplier<Pair<Integer, JsonNode>> handleGet(StateContext state) {
    JsonApiDocument doc = new JsonApiDocument();
    RequestScope requestScope = state.getRequestScope();
    JsonApiMapper mapper = requestScope.getMapper();
    MultivaluedMap<String, String> queryParams = requestScope.getQueryParams();
    Map<String, Relationship> relationships = record.toResource(parentProjection).getRelationships();
    if (relationships != null && relationships.containsKey(relationshipName)) {
        Relationship relationship = relationships.get(relationshipName);
        // Handle valid relationship
        // Set data
        Data<Resource> data = relationship.getData();
        doc.setData(data);
        // Run include processor
        DocumentProcessor includedProcessor = new IncludedProcessor();
        includedProcessor.execute(doc, record, queryParams);
        return () -> Pair.of(HttpStatus.SC_OK, mapper.toJsonObject(doc));
    }
    // Handle no data for relationship
    if (relationshipType.isToMany()) {
        doc.setData(new Data<>(new ArrayList<>()));
    } else if (relationshipType.isToOne()) {
        doc.setData(new Data<>((Resource) null));
    } else {
        throw new IllegalStateException("Failed to GET a relationship; relationship is neither toMany nor toOne");
    }
    return () -> Pair.of(HttpStatus.SC_OK, mapper.toJsonObject(doc));
}
Also used : JsonApiDocument(com.yahoo.elide.jsonapi.models.JsonApiDocument) DocumentProcessor(com.yahoo.elide.jsonapi.document.processors.DocumentProcessor) Resource(com.yahoo.elide.jsonapi.models.Resource) PersistentResource(com.yahoo.elide.core.PersistentResource) ArrayList(java.util.ArrayList) Data(com.yahoo.elide.jsonapi.models.Data) RequestScope(com.yahoo.elide.core.RequestScope) Relationship(com.yahoo.elide.jsonapi.models.Relationship) JsonApiMapper(com.yahoo.elide.jsonapi.JsonApiMapper) IncludedProcessor(com.yahoo.elide.jsonapi.document.processors.IncludedProcessor)

Aggregations

Relationship (com.yahoo.elide.jsonapi.models.Relationship)23 Resource (com.yahoo.elide.jsonapi.models.Resource)20 Test (org.junit.jupiter.api.Test)17 PatchRequestScope (com.yahoo.elide.jsonapi.extensions.PatchRequestScope)15 ArrayList (java.util.ArrayList)15 ResourceIdentifier (com.yahoo.elide.jsonapi.models.ResourceIdentifier)14 TestUser (com.yahoo.elide.core.security.TestUser)6 User (com.yahoo.elide.core.security.User)6 PersistentResource (com.yahoo.elide.core.PersistentResource)5 NoShareEntity (example.NoShareEntity)5 HashSet (java.util.HashSet)5 LinkedHashSet (java.util.LinkedHashSet)5 DataStoreIterableBuilder (com.yahoo.elide.core.datastore.DataStoreIterableBuilder)4 Data (com.yahoo.elide.jsonapi.models.Data)4 JsonApiDocument (com.yahoo.elide.jsonapi.models.JsonApiDocument)4 Map (java.util.Map)4 DataStoreTransaction (com.yahoo.elide.core.datastore.DataStoreTransaction)3 RelationshipType (com.yahoo.elide.core.dictionary.RelationshipType)3 InternalServerErrorException (com.yahoo.elide.core.exceptions.InternalServerErrorException)3 InvalidEntityBodyException (com.yahoo.elide.core.exceptions.InvalidEntityBodyException)3