All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.katharsis.dispatcher.controller.resource.ResourceUpsert Maven / Gradle / Ivy

There is a newer version: 3.0.2
Show newest version
package io.katharsis.dispatcher.controller.resource;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectReader;
import io.katharsis.dispatcher.controller.BaseController;
import io.katharsis.queryParams.QueryParams;
import io.katharsis.repository.RelationshipRepository;
import io.katharsis.repository.RepositoryMethodParameterProvider;
import io.katharsis.request.dto.DataBody;
import io.katharsis.request.dto.LinkageData;
import io.katharsis.resource.exception.ResourceException;
import io.katharsis.resource.exception.ResourceNotFoundException;
import io.katharsis.resource.field.ResourceField;
import io.katharsis.resource.information.ResourceInformation;
import io.katharsis.resource.registry.RegistryEntry;
import io.katharsis.resource.registry.ResourceRegistry;
import io.katharsis.utils.Generics;
import io.katharsis.utils.PropertyUtils;
import io.katharsis.utils.parser.TypeParser;

import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.util.*;

public abstract class ResourceUpsert implements BaseController {
    final ResourceRegistry resourceRegistry;
    final TypeParser typeParser;
    private final ObjectMapper objectMapper;

    public ResourceUpsert(ResourceRegistry resourceRegistry, TypeParser typeParser, ObjectMapper objectMapper) {
        this.resourceRegistry = resourceRegistry;
        this.typeParser = typeParser;
        this.objectMapper = objectMapper;
    }

    void setId(DataBody dataBody, Object instance, ResourceInformation resourceInformation) {
        if (dataBody.getId() != null) {
            String id = dataBody.getId();

            @SuppressWarnings("unchecked") Class idClass = (Class)
                resourceInformation
                    .getIdField()
                    .getType();
            Serializable castedId = typeParser.parse(id, idClass);
            PropertyUtils.setProperty(instance, resourceInformation.getIdField()
                .getName(), castedId);
        }
    }

    void setAttributes(DataBody dataBody, Object instance, ResourceInformation resourceInformation)
        throws IllegalAccessException, NoSuchMethodException, InvocationTargetException, InstantiationException,
        IOException {
        if (dataBody.getAttributes() != null) {
            ObjectReader reader = objectMapper.reader(instance.getClass());
            Object instanceWithNewFields = reader.readValue(dataBody.getAttributes());
            Iterator propertyNameIterator = dataBody.getAttributes()
                .fieldNames();
            while (propertyNameIterator.hasNext()) {
                String propertyName = propertyNameIterator.next();
                ResourceField attributeField = resourceInformation.findAttributeFieldByName(propertyName);
                Object property = PropertyUtils.getProperty(instanceWithNewFields, attributeField.getName());
                PropertyUtils.setProperty(instance, attributeField.getName(), property);
            }
        }
    }

    protected void saveRelations(Object savedResource, RegistryEntry registryEntry, DataBody dataBody,
                                 RepositoryMethodParameterProvider parameterProvider)
        throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        if (dataBody.getRelationships() != null) {
            Map additionalProperties = dataBody.getRelationships()
                .getAdditionalProperties();
            for (Map.Entry property : additionalProperties.entrySet()) {
                if (Iterable.class.isAssignableFrom(property.getValue()
                    .getClass())) {
                    //noinspection unchecked
                    saveRelationsField(savedResource, registryEntry, (Map.Entry) property, registryEntry
                        .getResourceInformation(), parameterProvider);
                } else {
                    //noinspection unchecked
                    saveRelationField(savedResource, registryEntry, (Map.Entry) property, registryEntry
                        .getResourceInformation(), parameterProvider);
                }

            }
        }
    }

    private void saveRelationsField(Object savedResource, RegistryEntry registryEntry,
                                    Map.Entry> property,
                                    ResourceInformation resourceInformation,
                                    RepositoryMethodParameterProvider parameterProvider)
        throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
        if (!allTypesTheSame(property.getValue())) {
            throw new ResourceException("Not all types are the same for linkage: " + property.getKey());
        }

        String type = getLinkageType(property.getValue());
        RegistryEntry relationRegistryEntry = getRelationRegistryEntry(type);
        @SuppressWarnings("unchecked")
        Class relationshipIdClass = (Class) relationRegistryEntry
            .getResourceInformation()
            .getIdField()
            .getType();
        List castedRelationIds = new LinkedList<>();

        for (LinkageData linkageData : property.getValue()) {
            Serializable castedRelationshipId = typeParser.parse(linkageData.getId(), relationshipIdClass);
            castedRelationIds.add(castedRelationshipId);
        }

        Class relationshipClass = relationRegistryEntry.getResourceInformation()
            .getResourceClass();
        RelationshipRepository relationshipRepository = registryEntry
            .getRelationshipRepositoryForClass(relationshipClass, parameterProvider);
        ResourceField relationshipField = resourceInformation.findRelationshipFieldByName(property.getKey());
        //noinspection unchecked
        relationshipRepository.setRelations(savedResource, castedRelationIds, relationshipField.getName());
    }

    private boolean allTypesTheSame(Iterable linkages) {
        String type = linkages.iterator()
            .hasNext() ? linkages.iterator()
            .next()
            .getType() : null;
        for (LinkageData linkageData : linkages) {
            if (!Objects.equals(type, linkageData.getType())) {
                return false;
            }
        }
        return true;
    }

    protected String getLinkageType(Iterable linkages) {
        return linkages.iterator()
            .hasNext() ? linkages.iterator()
            .next()
            .getType() : null;
    }

    private void saveRelationField(Object savedResource, RegistryEntry registryEntry,
                                   Map.Entry property, ResourceInformation resourceInformation,
                                   RepositoryMethodParameterProvider parameterProvider)
        throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
        RegistryEntry relationRegistryEntry = getRelationRegistryEntry(property.getValue()
            .getType());

        @SuppressWarnings("unchecked")
        Class relationshipIdClass = (Class) relationRegistryEntry
            .getResourceInformation()
            .getIdField()
            .getType();
        Serializable castedRelationshipId = typeParser.parse(property.getValue()
            .getId(), relationshipIdClass);

        Class relationshipClass = relationRegistryEntry.getResourceInformation()
            .getResourceClass();
        RelationshipRepository relationshipRepository = registryEntry
            .getRelationshipRepositoryForClass(relationshipClass, parameterProvider);
        ResourceField relationshipField = resourceInformation.findRelationshipFieldByName(property.getKey());
        //noinspection unchecked
        relationshipRepository.setRelation(savedResource, castedRelationshipId, relationshipField.getName());
    }

    private RegistryEntry getRelationRegistryEntry(String type) {
        RegistryEntry relationRegistryEntry = resourceRegistry.getEntry(type);
        if (relationRegistryEntry == null) {
            throw new ResourceNotFoundException(type);
        }
        return relationRegistryEntry;
    }

    Object buildNewResource(RegistryEntry registryEntry, DataBody dataBody, String resourceName)
        throws IllegalAccessException, NoSuchMethodException, InvocationTargetException, InstantiationException {
        if (dataBody == null) {
            throw new RuntimeException("No data field in the body.");
        }
        if (!resourceName.equals(dataBody.getType())) {
            throw new RuntimeException(String.format("Inconsistent type definition between path and body: body type: " +
                "%s, request type: %s", dataBody.getType(), resourceName));
        }
        return registryEntry.getResourceInformation()
            .getResourceClass()
            .newInstance();
    }

    protected void setRelations(Object newResource, RegistryEntry registryEntry, DataBody dataBody, QueryParams
        queryParams,
                                RepositoryMethodParameterProvider parameterProvider)
        throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        if (dataBody.getRelationships() != null) {
            Map additionalProperties = dataBody.getRelationships()
                .getAdditionalProperties();
            for (Map.Entry property : additionalProperties.entrySet()) {
                if (property.getValue() != null && Iterable.class.isAssignableFrom(property.getValue()
                    .getClass())) {
                    //noinspection unchecked
                    setRelationsField(newResource, registryEntry, (Map.Entry) property, queryParams, parameterProvider);
                } else {
                    //noinspection unchecked
                    setRelationField(newResource, registryEntry, (Map.Entry) property, queryParams, parameterProvider);
                }

            }
        }
    }

    private void setRelationsField(Object newResource, RegistryEntry registryEntry,
                                   Map.Entry> property, QueryParams queryParams,
                                   RepositoryMethodParameterProvider parameterProvider) {
        String propertyName = property.getKey();
        ResourceField relationshipField = registryEntry.getResourceInformation()
            .findRelationshipFieldByName(propertyName);
        Class relationshipFieldClass = Generics.getResourceClass(relationshipField.getGenericType(),
            relationshipField.getType());
        RegistryEntry entry = resourceRegistry.getEntry(relationshipFieldClass);
        Class idFieldType = entry.getResourceInformation()
            .getIdField()
            .getType();

        List relationships = new LinkedList<>();
        for (LinkageData linkageData : property.getValue()) {
            Serializable castedRelationshipId = typeParser.parse(linkageData.getId(), idFieldType);
            Object relationObject = entry.getResourceRepository(parameterProvider)
                .findOne(castedRelationshipId, queryParams);
            relationships.add(relationObject);
        }
        PropertyUtils.setProperty(newResource, propertyName, relationships);
    }

    private void setRelationField(Object newResource, RegistryEntry registryEntry,
                                  Map.Entry property, QueryParams queryParams,
                                  RepositoryMethodParameterProvider parameterProvider) {
        String propertyName = property.getKey();

        Object relationObject;
        if (property.getValue() != null) {
            ResourceField relationshipFieldByName = registryEntry.getResourceInformation()
                .findRelationshipFieldByName(propertyName);
            RegistryEntry entry = resourceRegistry.getEntry(relationshipFieldByName.getType());
            Class idFieldType = entry.getResourceInformation()
                .getIdField()
                .getType();
            Serializable castedRelationshipId = typeParser.parse(property.getValue()
                .getId(), idFieldType);
            relationObject = entry.getResourceRepository(parameterProvider)
                .findOne(castedRelationshipId, queryParams);
        } else {
            relationObject = null;
        }


        PropertyUtils.setProperty(newResource, propertyName, relationObject);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy