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

de.captaingoldfish.scim.sdk.server.endpoints.bulkget.ResourceReferenceExtractor Maven / Gradle / Ivy

There is a newer version: 1.26.0
Show newest version
// Generated by delombok at Thu Nov 02 20:38:53 CET 2023
package de.captaingoldfish.scim.sdk.server.endpoints.bulkget;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import de.captaingoldfish.scim.sdk.common.schemas.SchemaAttribute;
import de.captaingoldfish.scim.sdk.server.schemas.ResourceType;
import de.captaingoldfish.scim.sdk.server.schemas.ResourceTypeFactory;


/**
 * @author Pascal Knueppel
 * @since 30.08.2022
 */
class ResourceReferenceExtractor
{

  /**
   * this operation contains the parent whose children shall be extracted
   */
  private final ObjectNode resource;

  /**
   * the resources definition
   */
  private final ResourceType resourceType;

  /**
   * the factory is necessary to get the resource definitions of the transitive types to be able to analyze them
   * correctly
   */
  private final ResourceTypeFactory resourceTypeFactory;

  public ResourceReferenceExtractor(ObjectNode resource,
                                    ResourceType resourceType,
                                    ResourceTypeFactory resourceTypeFactory)
  {
    this.resource = resource;
    this.resourceType = resourceType;
    this.resourceTypeFactory = resourceTypeFactory;
  }

  /**
   * retrieves all child-references from the given {@link #resource}
   */
  public List getResourceReferences()
  {
    List resourceReferences = extractSimpleResourceReferences();
    resourceReferences.addAll(extractComplexResourceReferences());
    return resourceReferences;
  }

  /**
   * retrieves all child-references from the given {@link #resource} that are set with simple resource reference
   * fields
   */
  private List extractSimpleResourceReferences()
  {
    return Stream.concat(resourceType.getMainSchema()
                                     .getSimpleBulkIdCandidates()
                                     .stream()
                                     .flatMap(schemaAttribute -> toSimpleResourceReference(schemaAttribute,
                                                                                           false).stream()),
                         resourceType.getAllSchemaExtensions()
                                     .stream()
                                     .flatMap(schema -> schema.getSimpleBulkIdCandidates().stream())
                                     .flatMap(schemaAttribute -> toSimpleResourceReference(schemaAttribute,
                                                                                           true).stream()))
                 .collect(Collectors.toList());
  }

  /**
   * retrieves all child-references from the given {@link #resource} that are set with complex resource
   * reference fields
   */
  private List extractComplexResourceReferences()
  {
    return Stream.concat(resourceType.getMainSchema()
                                     .getComplexBulkIdCandidates()
                                     .stream()
                                     .flatMap(schemaAttribute -> toComplexResourceReference(schemaAttribute,
                                                                                            false).stream()),
                         resourceType.getAllSchemaExtensions()
                                     .stream()
                                     .flatMap(schema -> schema.getComplexBulkIdCandidates().stream())
                                     .flatMap(schemaAttribute -> toComplexResourceReference(schemaAttribute,
                                                                                            true).stream()))
                 .filter(Objects::nonNull)
                 .collect(Collectors.toList());
  }

  /**
   * retrieves complex resource references from either an extension or the main resource
   *
   * @param schemaAttribute the attributes definition
   * @param isExtensionAttribute if the attribute is from an extension or from the main schema
   * @return the retrieved child resource references
   */
  private List toComplexResourceReference(SchemaAttribute schemaAttribute,
                                                             boolean isExtensionAttribute)
  {
    if (isExtensionAttribute)
    {
      return getComplexAttributeReferenceFromExtension(schemaAttribute);
    }
    return getComplexAttributeReferenceFromResource(resource, schemaAttribute);
  }

  /**
   * tries to retrieve the given resource reference attribute from an extension within the resource
   *
   * @param schemaAttribute the resource reference attribute definition
   * @return the resource reference if it does exist or an empty if the extension or the attribute is not
   *         present
   */
  private List getComplexAttributeReferenceFromExtension(SchemaAttribute schemaAttribute)
  {
    String extensionUri = schemaAttribute.getSchema().getNonNullId();
    JsonNode extension = resource.get(extensionUri);
    if (extension == null)
    {
      return Collections.emptyList();
    }
    return getComplexAttributeReferenceFromResource((ObjectNode)extension, schemaAttribute);
  }

  /**
   * retrieves the child references from a complex node that might either be a single complex node or a
   * multivalued complex node
   *
   * @param objectNode the resource that should be either the main resource or an extension of the main resource
   * @param schemaAttribute the current attributes definition
   * @return the retrieved child references of the {@code schemaAttribute}
   */
  private List getComplexAttributeReferenceFromResource(ObjectNode objectNode,
                                                                           SchemaAttribute schemaAttribute)
  {
    JsonNode resource = objectNode.get(schemaAttribute.getName());
    if (resource == null)
    {
      return Collections.emptyList();
    }
    if (schemaAttribute.isMultiValued() && resource.isArray())
    {
      List resourceReferences = new ArrayList<>();
      for ( JsonNode multivaluedComplexNode : resource )
      {
        toResourceReference(schemaAttribute.getScimNodeName(),
                            (ObjectNode)multivaluedComplexNode).ifPresent(resourceReferences::add);
      }
      return resourceReferences;
    }
    else
    {
      return toResourceReference(schemaAttribute.getScimNodeName(),
                                 (ObjectNode)resource).map(Collections::singletonList).orElse(Collections.emptyList());
    }
  }

  /**
   * tries to resolve the complex type into a resolvable resource reference
   *
   * @param nodeName the name of the referenced node
   * @param complexNode the complex resource reference node to resolve
   * @return the resource reference if the resource type was resolvable or an empty of no resource type was
   *         found that matches the referenced data
   */
  private Optional toResourceReference(String nodeName, ObjectNode complexNode)
  {
    ResourceReference resourceReference = new BulkResourceReferenceComplex(resourceTypeFactory, nodeName, complexNode);
    if (resourceReference.getResourceType() == null)
    {
      // this case happens if the complex type does not contain a resolvable $ref or type attribute
      return Optional.empty();
    }
    return Optional.of(resourceReference);
  }

  /**
   * retrieves simple resource references from either an extension or the main resource
   *
   * @param schemaAttribute the attributes definition
   * @param isExtensionAttribute if the attribute is from an extension or from the main schema
   * @return the retrieved child resource references
   */
  private List toSimpleResourceReference(SchemaAttribute schemaAttribute,
                                                            boolean isExtensionAttribute)
  {
    if (isExtensionAttribute)
    {
      return getSimpleAttributeReferenceFromExtension(schemaAttribute);
    }
    return getSimpleAttributeReferenceFromResource(resource, schemaAttribute);
  }

  /**
   * retrieves simple resource references from an extension of the main resource
   *
   * @param schemaAttribute the current attributes definition
   * @return the list of found resource references
   */
  private List getSimpleAttributeReferenceFromExtension(SchemaAttribute schemaAttribute)
  {
    String extensionUri = schemaAttribute.getSchema().getNonNullId();
    JsonNode extension = resource.get(extensionUri);
    if (extension == null)
    {
      return Collections.emptyList();
    }
    return getSimpleAttributeReferenceFromResource((ObjectNode)extension, schemaAttribute);
  }

  /**
   * gets the resource references from an extension or the main resource
   *
   * @param objectNode an object node that is either the main resource or one of its extensions
   * @param schemaAttribute the current attributes definition
   * @return the found resource references
   */
  private List getSimpleAttributeReferenceFromResource(ObjectNode objectNode,
                                                                          SchemaAttribute schemaAttribute)
  {
    boolean hasParent = schemaAttribute.getParent() != null;
    final JsonNode resource;
    if (hasParent)
    {
      resource = objectNode.get(schemaAttribute.getParent().getName());
      if (schemaAttribute.getParent().isMultiValued() && resource != null && resource.isArray())
      {
        return getArrayNodeElementReferences((ArrayNode)resource, schemaAttribute);
      }
    }
    else
    {
      resource = objectNode;
    }
    if (resource == null)
    {
      return Collections.emptyList();
    }
    JsonNode attribute = resource.get(schemaAttribute.getName());
    if (attribute == null)
    {
      return Collections.emptyList();
    }
    if (schemaAttribute.isMultiValued() && attribute.isArray())
    {
      return getArrayNodeElementReferences((ArrayNode)attribute, schemaAttribute);
    }
    return Collections.singletonList(new BulkResourceReferenceSimple(resourceTypeFactory, resourceType,
                                                                     schemaAttribute.getScimNodeName(), attribute));
  }

  /**
   * retrieves the resource references from an array which elements are either complex nodes or simple nodes
   *
   * @param resource the array node that contains either complex or simple nodes
   * @param schemaAttribute the current attributes definition
   * @return the found resource references within the array
   */
  private List getArrayNodeElementReferences(ArrayNode resource, SchemaAttribute schemaAttribute)
  {
    List resourceReferences = new ArrayList<>();
    for ( JsonNode arrayElement : resource )
    {
      if (arrayElement.isObject()) // multivalued complex type
      {
        JsonNode attribute = arrayElement.get(schemaAttribute.getName());
        if (schemaAttribute.isMultiValued() && attribute.isArray())
        {
          resourceReferences.addAll(getArrayNodeElementReferences((ArrayNode)attribute, schemaAttribute));
        }
        else
        {
          resourceReferences.add(new BulkResourceReferenceSimple(resourceTypeFactory, resourceType,
                                                                 schemaAttribute.getScimNodeName(), attribute));
        }
      }
      else // simple multivalued type
      {
        resourceReferences.add(new BulkResourceReferenceSimple(resourceTypeFactory, resourceType,
                                                               schemaAttribute.getScimNodeName(), arrayElement));
      }
    }
    return resourceReferences;
  }


  @java.lang.SuppressWarnings("all")
  public static class ResourceReferenceExtractorBuilder
  {

    @java.lang.SuppressWarnings("all")
    private ObjectNode resource;

    @java.lang.SuppressWarnings("all")
    private ResourceType resourceType;

    @java.lang.SuppressWarnings("all")
    private ResourceTypeFactory resourceTypeFactory;

    @java.lang.SuppressWarnings("all")
    ResourceReferenceExtractorBuilder()
    {}

    /**
     * @return {@code this}.
     */
    @java.lang.SuppressWarnings("all")
    public ResourceReferenceExtractor.ResourceReferenceExtractorBuilder resource(final ObjectNode resource)
    {
      this.resource = resource;
      return this;
    }

    /**
     * @return {@code this}.
     */
    @java.lang.SuppressWarnings("all")
    public ResourceReferenceExtractor.ResourceReferenceExtractorBuilder resourceType(final ResourceType resourceType)
    {
      this.resourceType = resourceType;
      return this;
    }

    /**
     * @return {@code this}.
     */
    @java.lang.SuppressWarnings("all")
    public ResourceReferenceExtractor.ResourceReferenceExtractorBuilder resourceTypeFactory(final ResourceTypeFactory resourceTypeFactory)
    {
      this.resourceTypeFactory = resourceTypeFactory;
      return this;
    }

    @java.lang.SuppressWarnings("all")
    public ResourceReferenceExtractor build()
    {
      return new ResourceReferenceExtractor(this.resource, this.resourceType, this.resourceTypeFactory);
    }

    @java.lang.Override
    @java.lang.SuppressWarnings("all")
    public java.lang.String toString()
    {
      return "ResourceReferenceExtractor.ResourceReferenceExtractorBuilder(resource=" + this.resource
             + ", resourceType=" + this.resourceType + ", resourceTypeFactory=" + this.resourceTypeFactory + ")";
    }
  }

  @java.lang.SuppressWarnings("all")
  public static ResourceReferenceExtractor.ResourceReferenceExtractorBuilder builder()
  {
    return new ResourceReferenceExtractor.ResourceReferenceExtractorBuilder();
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy