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

com.unboundid.scim2.client.requests.RequestBuilder Maven / Gradle / Ivy

/*
 * Copyright 2015-2021 Ping Identity Corporation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License (GPLv2 only)
 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see .
 */

package com.unboundid.scim2.client.requests;

import com.unboundid.scim2.client.ScimServiceException;
import com.unboundid.scim2.common.ScimResource;
import com.unboundid.scim2.common.exceptions.ScimException;
import com.unboundid.scim2.common.messages.ErrorResponse;
import com.unboundid.scim2.common.utils.StaticUtils;

import javax.ws.rs.ProcessingException;
import javax.ws.rs.client.Invocation;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import static com.unboundid.scim2.common.utils.ApiConstants.MEDIA_TYPE_SCIM;

/**
 * Abstract SCIM request builder.
 */
public class RequestBuilder
{
  /**
   * The web target to send the request.
   */
  private WebTarget target;

  /**
   * Arbitrary request headers.
   */
  protected final MultivaluedMap headers =
      new MultivaluedHashMap();

  /**
   * Arbitrary query parameters.
   */
  protected final MultivaluedMap queryParams =
      new MultivaluedHashMap();

  private String contentType = MEDIA_TYPE_SCIM;

  private List accept = new ArrayList();

  /**
   * Create a new SCIM request builder.
   *
   * @param target The WebTarget to send the request.
   */
  RequestBuilder(final WebTarget target)
  {
    this.target = target;
    accept(MEDIA_TYPE_SCIM, MediaType.APPLICATION_JSON);
  }

  /**
   * Add an arbitrary HTTP header to the request.
   *
   * @param name The header name.
   * @param value The header value(s).
   * @return This builder.
   */
  @SuppressWarnings("unchecked")
  public T header(final String name, final Object... value)
  {
    headers.addAll(name, value);
    return (T) this;
  }

  /**
   * Sets the media type for any content sent to the server.  The default
   * value is ApiConstants.MEDIA_TYPE_SCIM ("application/scim+json").
   * @param contentType a string describing the media type of content
   *                    sent to the server.
   * @return This builder.
   */
  public T contentType(final String contentType)
  {
    this.contentType = contentType;
    return (T) this;
  }

  /**
   * Sets the media type(s) that are acceptable as a return from the server.
   * The default accepted media types are
   * ApiConstants.MEDIA_TYPE_SCIM ("application/scim+json") and
   * MediaType.APPLICATION_JSON ("application/json")
   * @param acceptStrings a string (or strings) describing the media type that
   *                      will be accepted from the server.  This parameter may
   *                      not be null.
   * @return This builder.
   */
  public T accept(final String ... acceptStrings)
  {
    this.accept.clear();
    if((acceptStrings == null) || (acceptStrings.length == 0))
    {
      throw new IllegalArgumentException(
          "Accepted media types must not be null or empty");
    }

    for(String acceptString : acceptStrings)
    {
      accept.add(acceptString);
    }

    return (T) this;
  }

  /**
   * Add an arbitrary query parameter to the request.
   *
   * @param name The query parameter name.
   * @param value The query parameter value(s).
   * @return This builder.
   */
  @SuppressWarnings("unchecked")
  public T queryParam(final String name, final Object... value)
  {
    queryParams.addAll(name, value);
    return (T) this;
  }

  /**
   * Retrieve the meta.version attribute of the resource.
   *
   * @param resource The resource whose version to retrieve.
   * @return The resource version.
   * @throws IllegalArgumentException if the resource does not contain a the
   * meta.version attribute.
   */
  static String getResourceVersion(final ScimResource resource)
      throws IllegalArgumentException
  {
    if(resource == null || resource.getMeta() == null ||
        resource.getMeta().getVersion() == null)
    {
      throw new IllegalArgumentException(
          "Resource version must be specified by meta.version");
    }
    return resource.getMeta().getVersion();
  }

  /**
   * Convert a JAX-RS response to a ScimException.
   *
   * @param response The JAX-RS response.
   * @return the converted ScimException.
   */
  static ScimException toScimException(final Response response)
  {
    try
    {
      ErrorResponse errorResponse = response.readEntity(ErrorResponse.class);
      // If are able to read an error response, use it to build the exception.
      // If not, use the http status code to determine the exception.
      ScimException exception = (errorResponse == null) ?
        ScimException.createException(response.getStatus(), null) :
        ScimException.createException(errorResponse, null);
      response.close();

      return exception;
    }
    catch(ProcessingException ex)
    {
      // The exception message likely contains unwanted details about why the
      // server failed to process the response, instead of the actual SCIM
      // issue. Replace it with a general reason phrase for the status code.
      String genericDetails = response.getStatusInfo().getReasonPhrase();

      return new ScimServiceException(
          response.getStatus(), genericDetails, ex);
    }
  }

  /**
   * Returns the unbuilt WebTarget for the request. In most cases,
   * {@link #buildTarget()} should be used instead.
   *
   * @return The WebTarget for the request.
   */
  protected WebTarget target()
  {
    return target;
  }

  /**
   * Build the WebTarget for the request.
   *
   * @return The WebTarget for the request.
   */
  WebTarget buildTarget()
  {
    for(Map.Entry> queryParam : queryParams.entrySet())
    {
      target = target.queryParam(queryParam.getKey(),
                                 queryParam.getValue().toArray());
    }
    return target;
  }

  /**
   * Gets the media type for any content sent to the server.
   *
   * @return the media type for any content sent to the server.
   */
  protected String getContentType()
  {
    return contentType;
  }

  /**
   * Gets the media type(s) that are acceptable as a return from the server.
   *
   * @return the media type(s) that are acceptable as a return from the server.
   */
  protected List getAccept()
  {
    return accept;
  }
  /**
   * Build the Invocation.Builder for the request.
   *
   * @return The Invocation.Builder for the request.
   */
  Invocation.Builder buildRequest()
  {
    Invocation.Builder builder =
        buildTarget().request(accept.toArray(new String[accept.size()]));
    for(Map.Entry> header : headers.entrySet())
    {
      builder = builder.header(header.getKey(),
                               StaticUtils.listToString(header.getValue(),
                                                        ", "));
    }
    return builder;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy