Search in sources :

Example 66 with Resource

use of io.crnk.core.engine.document.Resource in project crnk-framework by crnk-project.

the class ResourceUpsert method getRequestBody.

protected Resource getRequestBody(Document requestDocument, JsonPath path, HttpMethod method) {
    String resourceType = path.getResourceType();
    assertRequestDocument(requestDocument, method, resourceType);
    if (!requestDocument.getData().isPresent() || requestDocument.getData().get() == null) {
        throw new RequestBodyException(method, resourceType, "No data field in the body.");
    }
    if (requestDocument.getData().get() instanceof Collection) {
        throw new RequestBodyException(method, resourceType, "Multiple data in body");
    }
    Resource resourceBody = (Resource) requestDocument.getData().get();
    RegistryEntry bodyRegistryEntry = resourceRegistry.getEntry(resourceBody.getType());
    if (bodyRegistryEntry == null) {
        throw new RepositoryNotFoundException(resourceBody.getType());
    }
    return resourceBody;
}
Also used : RequestBodyException(io.crnk.core.exception.RequestBodyException) Resource(io.crnk.core.engine.document.Resource) RepositoryNotFoundException(io.crnk.core.exception.RepositoryNotFoundException) RegistryEntry(io.crnk.core.engine.registry.RegistryEntry)

Example 67 with Resource

use of io.crnk.core.engine.document.Resource in project crnk-framework by crnk-project.

the class IncludeLookupSetter method setupRelation.

private List<Resource> setupRelation(Resource sourceResource, ResourceField relationshipField, Object targetEntity, QueryAdapter queryAdapter, Map<ResourceIdentifier, Resource> resourceMap, Map<ResourceIdentifier, Object> entityMap, ResourceMappingConfig resourceMappingConfig) {
    // set the relation
    String relationshipName = relationshipField.getJsonName();
    Map<String, Relationship> relationships = sourceResource.getRelationships();
    Relationship relationship = relationships.get(relationshipName);
    if (targetEntity instanceof Iterable) {
        List<Resource> targets = new ArrayList<>();
        for (Object targetElement : (Iterable<?>) targetEntity) {
            Resource targetResource = mergeResource(targetElement, queryAdapter, resourceMap, entityMap, resourceMappingConfig);
            targets.add(targetResource);
        }
        relationship.setData(Nullable.of((Object) util.toIds(targets)));
        return targets;
    } else {
        Resource targetResource = mergeResource(targetEntity, queryAdapter, resourceMap, entityMap, resourceMappingConfig);
        relationship.setData(Nullable.of((Object) targetResource.toIdentifier()));
        return Collections.singletonList(targetResource);
    }
}
Also used : Relationship(io.crnk.core.engine.document.Relationship) Resource(io.crnk.core.engine.document.Resource) ArrayList(java.util.ArrayList)

Example 68 with Resource

use of io.crnk.core.engine.document.Resource in project crnk-framework by crnk-project.

the class IncludeLookupSetter method lookupRelatedResourceWithRelationship.

private Set<Resource> lookupRelatedResourceWithRelationship(Collection<Resource> sourceResources, ResourceField relationshipField, QueryAdapter queryAdapter, RepositoryMethodParameterProvider parameterProvider, Map<ResourceIdentifier, Resource> resourceMap, Map<ResourceIdentifier, Object> entityMap, ResourceMappingConfig resourceMappingConfig) {
    ResourceInformation resourceInformation = relationshipField.getParentResourceInformation();
    RegistryEntry registyEntry = resourceRegistry.getEntry(resourceInformation.getResourceType());
    List<Serializable> resourceIds = getIds(sourceResources, resourceInformation);
    boolean isMany = Iterable.class.isAssignableFrom(relationshipField.getType());
    Set<Resource> loadedTargets = new HashSet<>();
    @SuppressWarnings("rawtypes") RelationshipRepositoryAdapter relationshipRepository = registyEntry.getRelationshipRepository(relationshipField, parameterProvider);
    if (relationshipRepository != null) {
        Map<Object, JsonApiResponse> responseMap;
        if (isMany) {
            responseMap = relationshipRepository.findBulkManyTargets(resourceIds, relationshipField, queryAdapter);
        } else {
            responseMap = relationshipRepository.findBulkOneTargets(resourceIds, relationshipField, queryAdapter);
        }
        for (Resource sourceResource : sourceResources) {
            Serializable sourceId = resourceInformation.parseIdString(sourceResource.getId());
            JsonApiResponse targetResponse = responseMap.get(sourceId);
            if (targetResponse != null && targetResponse.getEntity() != null) {
                Object targetEntity = targetResponse.getEntity();
                List<Resource> targets = setupRelation(sourceResource, relationshipField, targetEntity, queryAdapter, resourceMap, entityMap, resourceMappingConfig);
                loadedTargets.addAll(targets);
            } else {
                Nullable<Object> emptyData = (Nullable) Nullable.of(Iterable.class.isAssignableFrom(relationshipField.getType()) ? Collections.emptyList() : null);
                Relationship relationship = sourceResource.getRelationships().get(relationshipField.getJsonName());
                relationship.setData(emptyData);
            }
        }
    } else {
        throw new RepositoryNotFoundException("no relationship repository found for " + resourceInformation.getResourceType() + "." + relationshipField.getUnderlyingName());
    }
    return loadedTargets;
}
Also used : ResourceInformation(io.crnk.core.engine.information.resource.ResourceInformation) Serializable(java.io.Serializable) Resource(io.crnk.core.engine.document.Resource) RepositoryNotFoundException(io.crnk.core.exception.RepositoryNotFoundException) RegistryEntry(io.crnk.core.engine.registry.RegistryEntry) RelationshipRepositoryAdapter(io.crnk.core.engine.internal.repository.RelationshipRepositoryAdapter) Relationship(io.crnk.core.engine.document.Relationship) JsonApiResponse(io.crnk.core.repository.response.JsonApiResponse) Nullable(io.crnk.core.utils.Nullable) HashSet(java.util.HashSet)

Example 69 with Resource

use of io.crnk.core.engine.document.Resource in project crnk-framework by crnk-project.

the class IncludeLookupSetter method populateField.

private void populateField(ResourceField resourceField, QueryAdapter queryAdapter, List<ResourceField> fieldPath, PopulatedCache populatedCache, Collection<Resource> resourceList, Set<String> fieldsWithEnforceIdSerialization, RepositoryMethodParameterProvider parameterProvider, Map<ResourceIdentifier, Resource> resourceMap, Map<ResourceIdentifier, Object> entityMap, Set<ResourceIdentifier> inclusions, ResourceMappingConfig resourceMappingConfig) {
    ResourceInformation resourceInformation = resourceField.getParentResourceInformation();
    boolean includeRequested = util.isInclusionRequested(queryAdapter, fieldPath);
    boolean includeResources = includeRequested || resourceField.getSerializeType() == SerializeType.EAGER;
    boolean includeRelationId = resourceField.getSerializeType() != SerializeType.LAZY || fieldsWithEnforceIdSerialization.contains(resourceField.getJsonName());
    boolean includeRelationshipData = includeRelationId || includeResources;
    if (includeRelationshipData) {
        Collection<Resource> unpopulatedResourceList = populatedCache.filterProcessed(resourceList, resourceField);
        if (!unpopulatedResourceList.isEmpty()) {
            // only handle resources from the proper subtype where the
            // relationship is desired to be loaded
            List<Resource> resourcesByType = util.filterByType(unpopulatedResourceList, resourceInformation);
            List<Resource> resourcesWithField = util.filterByLoadedRelationship(resourcesByType, resourceField);
            // lookup resources by inspecting the POJOs in entityMap
            LookupIncludeBehavior fieldLookupIncludeBehavior = resourceField.getLookupIncludeAutomatically();
            Set<Resource> populatedResources;
            if (!includeResources && resourceField.hasIdField()) {
                // fill in @JsonApiRelationId into Relationship where possible
                fetchRelationFromEntity(resourcesWithField, resourceField, queryAdapter, resourceMap, entityMap, false, false, includeResources, resourceMappingConfig);
                // only ID is required and no lookup must take place
                // nothing to do
                populatedResources = Collections.emptySet();
            } else if (fieldLookupIncludeBehavior == LookupIncludeBehavior.AUTOMATICALLY_ALWAYS) {
                // fill in @JsonApiRelationId into Relationship where possible
                fetchRelationFromEntity(resourcesWithField, resourceField, queryAdapter, resourceMap, entityMap, false, false, includeResources, resourceMappingConfig);
                // lookup resources by making repository calls
                populatedResources = lookupRelatedResource(resourcesWithField, resourceField, queryAdapter, parameterProvider, resourceMap, entityMap, resourceMappingConfig);
            } else if (fieldLookupIncludeBehavior == LookupIncludeBehavior.AUTOMATICALLY_WHEN_NULL) {
                // try to populate from entities
                Set<Resource> extractedResources = fetchRelationFromEntity(resourcesWithField, resourceField, queryAdapter, resourceMap, entityMap, true, true, includeResources, resourceMappingConfig);
                // do lookups where relationship data is null
                Collection<Resource> resourcesForLookup = util.findResourcesWithoutRelationshipToLoad(resourcesWithField, resourceField, resourceMap);
                Collection<Resource> lookedupResources = lookupRelatedResource(resourcesForLookup, resourceField, queryAdapter, parameterProvider, resourceMap, entityMap, resourceMappingConfig);
                populatedResources = util.union(lookedupResources, extractedResources);
            } else {
                // do not do any lookups
                populatedResources = fetchRelationFromEntity(resourcesWithField, resourceField, queryAdapter, resourceMap, entityMap, false, true, includeResources, resourceMappingConfig);
                // and be sure.
                if (!Iterable.class.isAssignableFrom(resourceField.getType())) {
                    Nullable<Object> emptyData = Nullable.nullValue();
                    for (Resource resourceWithField : resourcesWithField) {
                        Relationship relationship = resourceWithField.getRelationships().get(resourceField.getJsonName());
                        if (!relationship.getData().isPresent()) {
                            relationship.setData(emptyData);
                        }
                    }
                }
            }
            // such
            if (includeResources && !populatedResources.isEmpty()) {
                inclusions.addAll(util.toIds(populatedResources));
                Set<String> additionalEagerLoadedNestedRelations = Collections.emptySet();
                populate(populatedResources, inclusions, resourceMap, entityMap, fieldPath, queryAdapter, parameterProvider, additionalEagerLoadedNestedRelations, populatedCache, resourceMappingConfig);
            }
        }
    }
}
Also used : ResourceInformation(io.crnk.core.engine.information.resource.ResourceInformation) Resource(io.crnk.core.engine.document.Resource) Relationship(io.crnk.core.engine.document.Relationship) LookupIncludeBehavior(io.crnk.core.resource.annotations.LookupIncludeBehavior)

Example 70 with Resource

use of io.crnk.core.engine.document.Resource in project crnk-framework by crnk-project.

the class IncludeLookupSetter method fetchRelationFromEntity.

/**
 * No lookup specified for the field. Attempt to load relationship from
 * original POJOs. Throw an InternalServerErrorException if the field is an
 * Iterable and null.
 */
private Set<Resource> fetchRelationFromEntity(List<Resource> sourceResources, ResourceField relationshipField, QueryAdapter queryAdapter, Map<ResourceIdentifier, Resource> resourceMap, Map<ResourceIdentifier, Object> entityMap, boolean allowLookup, boolean fetchRelatedEntity, boolean mustInclude, ResourceMappingConfig resourceMappingConfig) {
    Set<Resource> loadedResources = new HashSet<>();
    for (Resource sourceResource : sourceResources) {
        ResourceIdentifier id = sourceResource.toIdentifier();
        Object sourceEntity = entityMap.get(id);
        if (sourceEntity != null && !(sourceEntity instanceof Resource)) {
            Object relatedEntity = null;
            if (fetchRelatedEntity) {
                relatedEntity = relationshipField.getAccessor().getValue(sourceEntity);
                if (!allowLookup && Iterable.class.isAssignableFrom(relationshipField.getType()) && relatedEntity == null) {
                    // note that single-valued relations are allowed to be null
                    throw new InternalServerErrorException(id + " relationship field collection '" + relationshipField.getJsonName() + "' can not be null. Either set the relationship as an empty " + Iterable.class.getCanonicalName() + " or add annotation @" + JsonApiLookupIncludeAutomatically.class.getCanonicalName());
                }
            }
            // attempt to work with full relationship and fallback to relationshipId where possible
            if (relatedEntity != null) {
                List<Resource> relatedResources = setupRelation(sourceResource, relationshipField, relatedEntity, queryAdapter, resourceMap, entityMap, resourceMappingConfig);
                loadedResources.addAll(relatedResources);
            } else if (relationshipField.hasIdField()) {
                Object relatedEntityID = relationshipField.getIdAccessor().getValue(sourceEntity);
                setupRelationId(sourceResource, relationshipField, relatedEntityID);
                if (fetchRelatedEntity && relatedEntityID != null && !allowLookup && mustInclude) {
                    throw new IllegalStateException("inconsistent relationship '" + relationshipField.getUnderlyingName() + "' for " + id + ", id " + "set to " + relatedEntityID + ", but related object is null and lookup disabled");
                }
            }
        }
    }
    return loadedResources;
}
Also used : ResourceIdentifier(io.crnk.core.engine.document.ResourceIdentifier) Resource(io.crnk.core.engine.document.Resource) InternalServerErrorException(io.crnk.core.exception.InternalServerErrorException) HashSet(java.util.HashSet)

Aggregations

Resource (io.crnk.core.engine.document.Resource)130 Document (io.crnk.core.engine.document.Document)86 Test (org.junit.Test)85 Relationship (io.crnk.core.engine.document.Relationship)48 Response (io.crnk.core.engine.dispatcher.Response)43 QuerySpec (io.crnk.core.queryspec.QuerySpec)43 ResourceIdentifier (io.crnk.core.engine.document.ResourceIdentifier)42 JsonPath (io.crnk.core.engine.internal.dispatcher.path.JsonPath)41 BaseControllerTest (io.crnk.core.engine.internal.dispatcher.controller.BaseControllerTest)37 Task (io.crnk.core.mock.models.Task)32 ResourcePost (io.crnk.core.engine.internal.dispatcher.controller.ResourcePost)31 Project (io.crnk.core.mock.models.Project)24 JsonApiResponse (io.crnk.core.repository.response.JsonApiResponse)17 LazyTask (io.crnk.core.mock.models.LazyTask)15 ResourceInformation (io.crnk.core.engine.information.resource.ResourceInformation)14 ResourcePatch (io.crnk.core.engine.internal.dispatcher.controller.ResourcePatch)14 RelationIdTestResource (io.crnk.core.mock.models.RelationIdTestResource)13 ResourceField (io.crnk.core.engine.information.resource.ResourceField)12 RegistryEntry (io.crnk.core.engine.registry.RegistryEntry)11 ResourceRepositoryAdapter (io.crnk.core.engine.internal.repository.ResourceRepositoryAdapter)10