001/*
002 * Copyright 2015-2023 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.exceptions.ScimException;
022
023import javax.ws.rs.client.Invocation;
024import javax.ws.rs.client.WebTarget;
025import javax.ws.rs.core.HttpHeaders;
026import javax.ws.rs.core.Response;
027
028/**
029 * A builder for SCIM retrieve requests.
030 */
031public abstract class RetrieveRequestBuilder
032    <T extends RetrieveRequestBuilder<T>>
033    extends ResourceReturningRequestBuilder<T>
034{
035  /**
036   * The version to match.
037   */
038  protected String version;
039
040  /**
041   * Create a new RetrieveRequestBuilder.
042   *
043   * @param target The WebTarget to GET.
044   */
045  private RetrieveRequestBuilder(final WebTarget target)
046  {
047    super(target);
048  }
049
050  /**
051   * {@inheritDoc}
052   */
053  @Override
054  Invocation.Builder buildRequest()
055  {
056    Invocation.Builder request = super.buildRequest();
057    if(version != null)
058    {
059      request.header(HttpHeaders.IF_NONE_MATCH, version);
060    }
061    return request;
062  }
063
064
065  /**
066   * A builder for SCIM retrieve requests for where the returned resource POJO
067   * type will be the same as the original.
068   */
069  public static final class Generic<T extends ScimResource>
070      extends RetrieveRequestBuilder<Generic<T>>
071  {
072    private final T resource;
073
074    /**
075     * Create a new generic retrieve request builder.
076     *
077     * @param target The WebTarget to GET.
078     * @param resource The SCIM resource to retrieve.
079     */
080    public Generic(final WebTarget target, final T resource)
081    {
082      super(target);
083      this.resource = resource;
084    }
085
086    /**
087     * Retrieve the resource only if the resource has been modified from the
088     * resource provided. If the resource has not been modified, the provided
089     * resource will be returned by invoke.
090     *
091     * @return This builder.
092     */
093    public Generic<T> ifNoneMatch()
094    {
095      version = getResourceVersion(resource);
096      return this;
097    }
098
099    /**
100     * Invoke the SCIM retrieve request.
101     *
102     * @return The successfully retrieved SCIM resource or the resource provided
103     *         if the ifNoneMatch method was called and the resource has not
104     *         been modified.
105     * @throws ScimException If an error occurred.
106     */
107    @SuppressWarnings("unchecked")
108    public T invoke() throws ScimException
109    {
110      return (T) invoke(resource.getClass());
111    }
112
113    /**
114     * Invoke the SCIM modify request.
115     *
116     * @param <C> The type of object to return.
117     * @param cls The Java class object used to determine the type to return.
118     * @return The successfully modified SCIM resource.
119     * @throws javax.ws.rs.ProcessingException If a JAX-RS runtime exception occurred.
120     * @throws javax.ws.rs.ProcessingException If a JAX-RS runtime exception occurred.
121     * @throws ScimException If the SCIM service provider responded with an error.
122     */
123    public <C> C invoke(final Class<C> cls) throws ScimException
124    {
125      Response response = buildRequest().get();
126      try
127      {
128        if(response.getStatusInfo().getFamily() ==
129            Response.Status.Family.SUCCESSFUL)
130        {
131          return response.readEntity(cls);
132        }
133        else
134        {
135          throw toScimException(response);
136        }
137      }
138      finally
139      {
140        response.close();
141      }
142    }
143  }
144
145
146  /**
147   * A builder for SCIM retrieve requests for where the returned resource POJO
148   * type will be provided.
149   */
150  public static final class Typed extends RetrieveRequestBuilder<Typed>
151  {
152    /**
153     * Create a new generic retrieve request builder.
154     *
155     * @param target The WebTarget to GET.
156     */
157    public Typed(final WebTarget target)
158    {
159      super(target);
160    }
161
162    /**
163     * Retrieve the resource only if the resource has been modified since the
164     * provided version. If the resource has not been modified,
165     * NotModifiedException will be thrown when calling invoke.
166     *
167     * @param version The version of the resource to compare.
168     * @return This builder.
169     */
170    public Typed ifNoneMatch(final String version)
171    {
172      this.version = version;
173      return this;
174    }
175
176    /**
177     * Invoke the SCIM retrieve request.
178     *
179     * @param <T> The type of object to return.
180     * @param cls The Java class object used to determine the type to return.
181     * @return The successfully retrieved SCIM resource.
182     * @throws javax.ws.rs.ProcessingException If a JAX-RS runtime exception occurred.
183     * @throws ScimException If the SCIM service provider responded with an error.
184     */
185    public <T> T invoke(final Class<T> cls) throws ScimException
186    {
187      Response response = buildRequest().get();
188      try
189      {
190        if(response.getStatusInfo().getFamily() ==
191            Response.Status.Family.SUCCESSFUL)
192        {
193          return response.readEntity(cls);
194        }
195        else
196        {
197          throw toScimException(response);
198        }
199      }
200      finally
201      {
202        response.close();
203      }
204    }
205  }
206}