001/*
002 * Copyright 2015-2024 Ping Identity Corporation
003 *
004 * This program is free software; you can redistribute it and/or modify
005 * it under the terms of the GNU General Public License (GPLv2 only)
006 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
007 * as published by the Free Software Foundation.
008 *
009 * This program is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
012 * GNU General Public License for more details.
013 *
014 * You should have received a copy of the GNU General Public License
015 * along with this program; if not, see <http://www.gnu.org/licenses>.
016 */
017
018package com.unboundid.scim2.client.requests;
019
020import com.unboundid.scim2.common.ScimResource;
021import com.unboundid.scim2.common.annotations.NotNull;
022import com.unboundid.scim2.common.annotations.Nullable;
023import com.unboundid.scim2.common.exceptions.ScimException;
024
025import jakarta.ws.rs.ProcessingException;
026import jakarta.ws.rs.client.Entity;
027import jakarta.ws.rs.client.Invocation;
028import jakarta.ws.rs.client.WebTarget;
029import jakarta.ws.rs.core.HttpHeaders;
030import jakarta.ws.rs.core.Response;
031
032/**
033 * A builder for SCIM replace requests.
034 */
035public final class ReplaceRequestBuilder<T extends ScimResource>
036    extends ResourceReturningRequestBuilder<ReplaceRequestBuilder<T>>
037{
038  @NotNull
039  private final T resource;
040
041  @Nullable
042  private String version;
043
044  /**
045   * Create a new replace request builder.
046   *
047   * @param target The WebTarget to PUT.
048   * @param resource The SCIM resource to replace.
049   */
050  public ReplaceRequestBuilder(@NotNull final WebTarget target,
051                               @NotNull final T resource)
052  {
053    super(target);
054    this.resource = resource;
055  }
056
057  /**
058   * Replace the resource only if the resource has not been modified from the
059   * resource provided.
060   *
061   * @return This builder.
062   */
063  @NotNull
064  public ReplaceRequestBuilder<T> ifMatch()
065  {
066    version = getResourceVersion(resource);
067    return this;
068  }
069
070  /**
071   * {@inheritDoc}
072   */
073  @Override
074  @NotNull
075  Invocation.Builder buildRequest()
076  {
077    Invocation.Builder request = super.buildRequest();
078    if(version != null)
079    {
080      request.header(HttpHeaders.IF_MATCH, version);
081    }
082    return request;
083  }
084
085  /**
086   * Invoke the SCIM replace request.
087   *
088   * @return The successfully replaced SCIM resource.
089   * @throws ScimException If an error occurred.
090   */
091  @NotNull
092  @SuppressWarnings("unchecked")
093  public T invoke() throws ScimException
094  {
095    return (T) invoke(resource.getClass());
096  }
097
098  /**
099   * Invoke the SCIM modify request.
100   *
101   * @param <C> The type of object to return.
102   * @param cls The Java class object used to determine the type to return.
103   * @return The successfully modified SCIM resource.
104   * @throws ProcessingException If a JAX-RS runtime exception occurred.
105   * @throws ScimException If the SCIM service provider responded with an error.
106   */
107  @NotNull
108  public <C> C invoke(@NotNull final Class<C> cls) throws ScimException
109  {
110    Response response = buildRequest().put(
111        Entity.entity(resource, getContentType()));
112    try
113    {
114      if(response.getStatusInfo().getFamily() ==
115          Response.Status.Family.SUCCESSFUL)
116      {
117        return response.readEntity(cls);
118      }
119      else
120      {
121        throw toScimException(response);
122      }
123    }
124    finally
125    {
126      response.close();
127    }
128  }
129}