Package org.restlet.client.resource

Source Code of org.restlet.client.resource.ClientResource

/**
* Copyright 2005-2012 Restlet S.A.S.
*
* The contents of this file are subject to the terms of one of the following
* open source licenses: Apache 2.0 or LGPL 3.0 or LGPL 2.1 or CDDL 1.0 or EPL
* 1.0 (the "Licenses"). You can select the license that you prefer but you may
* not use this file except in compliance with one of these Licenses.
*
* You can obtain a copy of the Apache 2.0 license at
* http://www.opensource.org/licenses/apache-2.0
*
* You can obtain a copy of the LGPL 3.0 license at
* http://www.opensource.org/licenses/lgpl-3.0
*
* You can obtain a copy of the LGPL 2.1 license at
* http://www.opensource.org/licenses/lgpl-2.1
*
* You can obtain a copy of the CDDL 1.0 license at
* http://www.opensource.org/licenses/cddl1
*
* You can obtain a copy of the EPL 1.0 license at
* http://www.opensource.org/licenses/eclipse-1.0
*
* See the Licenses for the specific language governing permissions and
* limitations under the Licenses.
*
* Alternatively, you can obtain a royalty free commercial license with less
* limitations, transferable or non-transferable, directly at
* http://www.restlet.com/products/restlet-framework
*
* Restlet is a registered trademark of Restlet S.A.S.
*/

package org.restlet.client.resource;

import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;

import org.restlet.client.Client;
import org.restlet.client.Context;
import org.restlet.client.Request;
import org.restlet.client.Response;
import org.restlet.client.Restlet;
import org.restlet.client.Uniform;
import org.restlet.client.data.ChallengeResponse;
import org.restlet.client.data.ChallengeScheme;
import org.restlet.client.data.ClientInfo;
import org.restlet.client.data.Conditions;
import org.restlet.client.data.Cookie;
import org.restlet.client.data.MediaType;
import org.restlet.client.data.Metadata;
import org.restlet.client.data.Method;
import org.restlet.client.data.Parameter;
import org.restlet.client.data.Protocol;
import org.restlet.client.data.Range;
import org.restlet.client.data.Reference;
import org.restlet.client.data.Status;
import org.restlet.client.representation.Representation;
import org.restlet.client.representation.StringRepresentation;
import org.restlet.client.representation.Variant;
import org.restlet.client.util.Series;

/**
* Client-side resource. Acts like a proxy of a target resource.<br>
* This class changes the semantics of the {@link Resource#getRequest()} and
* {@link Resource#getResponse()} methods. Since a clientResource may receive
* severals responses for a single request (in case of interim response), the
* {@link #getResponse()} method returns the last received response object. The
* Request object returned by the {@link #getRequest()} is actually a prototype
* which is cloned (except the representation) just before the {@link #handle()}
* method is called.<br>
* Users must be aware that by most representations can only be read or written
* once. Some others, such as {@link StringRepresentation} stored the entity in
* memory which can be read several times but has the drawback to consume
* memory.<br>
* Concurrency note: instances of the class are not designed to be shared among
* several threads. If thread-safety is necessary, consider using the
* lower-level {@link Client} class instead.
*
* @author Jerome Louvel
*/
@SuppressWarnings("deprecation")
public class ClientResource extends UniformResource {




    /** Indicates if redirections should be automatically followed. */
    private volatile boolean followingRedirects;

    /**
     * Indicates if maximum number of redirections that can be automatically
     * followed for a single call.
     */
    private volatile int maxRedirects;

    /** The next Restlet. */
    private volatile Uniform next;

    /** Indicates if the next Restlet has been created. */
    private volatile boolean nextCreated;



    /** Number of retry attempts before reporting an error. */
    private volatile int retryAttempts;

    /** Delay in milliseconds between two retry attempts. */
    private volatile long retryDelay;

    /** Indicates if idempotent requests should be retried on error. */
    private volatile boolean retryOnError;

    /**
     * Empty constructor.
     */
    protected ClientResource() {
    }

    /**
     * Constructor.
     *
     * @param resource
     *            The client resource to copy.
     */
    public ClientResource(ClientResource resource) {
        Request request = new Request(resource.getRequest());
        Response response = new Response(request);
        this.next = resource.getNext();
        this.followingRedirects = resource.isFollowingRedirects();
        this.maxRedirects = resource.getMaxRedirects();
        this.retryOnError = resource.isRetryOnError();
        this.retryDelay = resource.getRetryDelay();
        this.retryAttempts = resource.getRetryAttempts();

        init(resource.getContext(), request, response);
    }



    /**
     * Constructor.
     *
     * @param context
     *            The context.
     * @param method
     *            The method to call.
     * @param reference
     *            The target reference.
     */
    public ClientResource(Context context, Method method, Reference reference) {
        this(context, new Request(method, reference), new Response(null));
    }

    /**
     * Constructor.
     *
     * @param context
     *            The context.
     * @param method
     *            The method to call.
     * @param uri
     *            The target URI.
     */
    public ClientResource(Context context, Method method, String uri) {
        this(context, method, new Reference(uri));
    }

    /**
     * Constructor.
     *
     * @param context
     *            The context.
     * @param reference
     *            The target reference.
     */
    public ClientResource(Context context, Reference reference) {
        this(context, Method.GET, reference);
    }

    /**
     * Constructor.
     *
     * @param context
     *            The current context.
     * @param request
     *            The handled request.
     */
    public ClientResource(Context context, Request request) {
        this(context, request, null);
    }

    /**
     * Constructor.
     *
     * @param context
     *            The current context.
     * @param request
     *            The handled request.
     * @param response
     *            The handled response.
     */
    public ClientResource(Context context, Request request, Response response) {
        if (context == null) {
            context = Context.getCurrent();
        }

        // Don't remove this line.
        // See other constructor ClientResource(Context, Method, Reference)
        response.setRequest(request);

        this.followingRedirects = true;
        this.maxRedirects = 10;
        this.retryOnError = true;
        this.retryDelay = 2000L;
        this.retryAttempts = 2;
        init(context, request, response);
    }

    /**
     * Constructor.
     *
     * @param context
     *            The context.
     * @param uri
     *            The target URI.
     */
    public ClientResource(Context context, String uri) {
        this(context, Method.GET, uri);
    }



    /**
     * Constructor.
     *
     * @param method
     *            The method to call.
     * @param reference
     *            The target reference.
     */
    public ClientResource(Method method, Reference reference) {
        this(Context.getCurrent(), method, reference);
    }

    /**
     * Constructor.
     *
     * @param method
     *            The method to call.
     * @param uri
     *            The target URI.
     */
    public ClientResource(Method method, String uri) {
        this(Context.getCurrent(), method, uri);
    }

    /**
     * Constructor.
     *
     * @param reference
     *            The target reference.
     */
    public ClientResource(Reference reference) {
        this(Context.getCurrent(), null, reference);
    }

    /**
     * Constructor.
     *
     * @param request
     *            The handled request.
     */
    public ClientResource(Request request) {
        this(request, null);
    }

    /**
     * Constructor.
     *
     * @param request
     *            The handled request.
     * @param response
     *            The handled response.
     */
    public ClientResource(Request request, Response response) {
        this(Context.getCurrent(), request, response);
    }

    /**
     * Constructor.
     *
     * @param uri
     *            The target URI.
     */
    public ClientResource(String uri) {
        this(Context.getCurrent(), Method.GET, uri);
    }

    /**
     * Updates the client preferences to accept the given metadata (media types,
     * character sets, etc.) with a 1.0 quality in addition to existing ones.
     *
     * @param metadata
     *            The metadata to accept.
     * @see ClientInfo#accept(Metadata...)
     */
    public void accept(Metadata... metadata) {
        getClientInfo().accept(metadata);
    }

    /**
     * Updates the client preferences to accept the given metadata (media types,
     * character sets, etc.) with a given quality in addition to existing ones.
     *
     * @param metadata
     *            The metadata to accept.
     * @param quality
     *            The quality to set.
     * @see ClientInfo#accept(Metadata, float)
     */
    public void accept(Metadata metadata, float quality) {
        getClientInfo().accept(metadata, quality);
    }

    /**
     * Adds a parameter to the query component. The name and value are
     * automatically encoded if necessary.
     *
     * @param parameter
     *            The parameter to add.
     * @return The updated reference.
     * @see Reference#addQueryParameter(Parameter)
     */
    public Reference addQueryParameter(Parameter parameter) {
        return getReference().addQueryParameter(parameter);
    }

    /**
     * Adds a parameter to the query component. The name and value are
     * automatically encoded if necessary.
     *
     * @param name
     *            The parameter name.
     * @param value
     *            The optional parameter value.
     * @return The updated reference.
     * @see Reference#addQueryParameter(String, String)
     */
    public Reference addQueryParameter(String name, String value) {
        return getReference().addQueryParameter(name, value);
    }

    /**
     * Adds several parameters to the query component. The name and value are
     * automatically encoded if necessary.
     *
     * @param parameters
     *            The parameters to add.
     * @return The updated reference.
     * @see Reference#addQueryParameters(Iterable)
     */
    public Reference addQueryParameters(Iterable<Parameter> parameters) {
        return getReference().addQueryParameters(parameters);
    }

    /**
     * Adds a segment at the end of the path. If the current path doesn't end
     * with a slash character, one is inserted before the new segment value. The
     * value is automatically encoded if necessary.
     *
     * @param value
     *            The segment value to add.
     * @return The updated reference.
     * @see Reference#addSegment(String)
     */
    public Reference addSegment(String value) {
        return getReference().addSegment(value);
    }

    /**
     * Creates a next Restlet is no one is set. By default, it creates a new
     * {@link Client} based on the protocol of the resource's URI reference.
     *
     * @return The created next Restlet or null.
     */
    protected Uniform createNext() {
        Uniform result = null;


        if ((result == null) && (getContext() != null)) {
            // Try using directly the client dispatcher
            result = getContext().getClientDispatcher();
        }

        if (result == null) {
            // As a final option, try creating a client connector
             if (getReference().isRelative()) {
             getReference().setBaseRef(
             com.google.gwt.core.client.GWT.getHostPageBaseURL());
             setReference(getReference().getTargetRef());
             }

            Protocol rProtocol = getProtocol();
            Reference rReference = getReference();
            Protocol protocol = (rProtocol != null) ? rProtocol
                    : (rReference != null) ? rReference.getSchemeProtocol()
                            : null;

            if (protocol != null) {
                 result = new Client(protocol);
            }
        }

        return result;
    }

    /**
     * Creates a new request by cloning the one wrapped by this class.
     *
     * @return The new response.
     * @see #getRequest()
     */
    public Request createRequest() {
        return createRequest(getRequest());
    }

    /**
     * Creates a new request by cloning the given one.
     *
     * @param prototype
     *            The prototype request.
     * @return The new response.
     * @deprecated Use {@link #createRequest()} instead
     */
    @Deprecated
    public Request createRequest(Request prototype) {
        return new Request(prototype);
    }

    /**
     * Creates a new response for the given request.
     *
     * @param request
     *            The associated request.
     * @return The new response.
     */
    protected Response createResponse(Request request) {
        return new Response(request);
    }

    /**
     * Deletes the target resource and all its representations. If a success
     * status is not returned, then a resource exception is thrown.
     *
     * @return The optional response entity.
     * @see <a
     *      href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.7">HTTP
     *      DELETE method</a>
     */
    public Representation delete() throws ResourceException {
        return handle(Method.DELETE);
    }


    /**
     * Deletes the target resource and all its representations. If a success
     * status is not returned, then a resource exception is thrown.
     *
     * @param mediaType
     *            The media type of the representation to retrieve.
     * @return The representation matching the given media type.
     * @throws ResourceException
     * @see <a
     *      href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.7">HTTP
     *      DELETE method</a>
     */
    public Representation delete(MediaType mediaType) throws ResourceException {
        return handle(Method.DELETE, mediaType);
    }

    /**
     * By default, it throws a new resource exception. This can be overridden to
     * provide a different behavior.
     */
    @Override
    public void doError(Status errorStatus) {
        throw new ResourceException(errorStatus);
    }

    /**
     * Releases the resource by stopping any connector automatically created and
     * associated to the "next" property (see {@link #getNext()} method.
     */
    @Override
    protected void doRelease() throws ResourceException {
        if ((getNext() != null) && this.nextCreated) {
            if (getNext() instanceof Restlet) {
                try {
                    ((Restlet) getNext()).stop();
                } catch (Exception e) {
                    throw new ResourceException(e);
                }
            }

            setNext(null);
        }
    }

    /**
     * Attempts to {@link #release()} the resource.
     */
    @Override
    protected void finalize() throws Throwable {
        release();
    }

    /**
     * Represents the resource using content negotiation to select the best
     * variant based on the client preferences. Note that the client preferences
     * will be automatically adjusted, but only for this request. If you want to
     * change them once for all, you can use the {@link #getClientInfo()}
     * method.<br>
     * <br>
     * If a success status is not returned, then a resource exception is thrown.
     *
     * @return The best representation.
     * @throws ResourceException
     * @see <a
     *      href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.3">HTTP
     *      GET method</a>
     */
    public Representation get() throws ResourceException {
        return handle(Method.GET);
    }


    /**
     * Represents the resource using a given media type. Note that the client
     * preferences will be automatically adjusted, but only for this request. If
     * you want to change them once for all, you can use the
     * {@link #getClientInfo()} method.<br>
     * <br>
     * If a success status is not returned, then a resource exception is thrown.
     *
     * @param mediaType
     *            The media type of the representation to retrieve.
     * @return The representation matching the given media type.
     * @throws ResourceException
     * @see <a
     *      href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.3">HTTP
     *      GET method</a>
     */
    public Representation get(MediaType mediaType) throws ResourceException {
        return handle(Method.GET, mediaType);
    }

    /**
     * Returns the attribute value by looking up the given name in the response
     * attributes maps. The toString() method is then invoked on the attribute
     * value.
     *
     * @param name
     *            The attribute name.
     * @return The response attribute value.
     */
    public String getAttribute(String name) {
        Object value = getRequestAttributes().get(name);
        return (value == null) ? null : value.toString();
    }

    /**
     * Returns the child resource defined by its URI relatively to the current
     * resource. The child resource is defined in the sense of hierarchical
     * URIs. If the resource URI is not hierarchical, then an exception is
     * thrown.
     *
     * @param relativeRef
     *            The URI reference of the child resource relatively to the
     *            current resource seen as the parent resource.
     * @return The child resource.
     * @throws ResourceException
     */
    public ClientResource getChild(Reference relativeRef)
            throws ResourceException {
        ClientResource result = null;

        if ((relativeRef != null) && relativeRef.isRelative()) {
            result = new ClientResource(this);
            result.setReference(new Reference(getReference().getTargetRef(),
                    relativeRef).getTargetRef());
        } else {
            doError(Status.CLIENT_ERROR_BAD_REQUEST,
                    "The child URI is not relative.");
        }

        return result;
    }


    /**
     * Returns the child resource defined by its URI relatively to the current
     * resource. The child resource is defined in the sense of hierarchical
     * URIs. If the resource URI is not hierarchical, then an exception is
     * thrown.
     *
     * @param relativeUri
     *            The URI of the child resource relatively to the current
     *            resource seen as the parent resource.
     * @return The child resource.
     * @throws ResourceException
     */
    public ClientResource getChild(String relativeUri) throws ResourceException {
        return getChild(new Reference(relativeUri));
    }


    /**
     * Returns the maximum number of redirections that can be automatically
     * followed for a single call. Default value is 10.
     *
     * @return The maximum number of redirections that can be automatically
     *         followed for a single call.
     */
    public int getMaxRedirects() {
        return maxRedirects;
    }

    /**
     * Returns the next Restlet. By default, it is the client dispatcher if a
     * context is available.
     *
     * @return The next Restlet or null.
     */
    public Uniform getNext() {
        Uniform result = this.next;

        if (result == null) {
            synchronized (this) {
                if (result == null) {
                    result = createNext();

                    if (result != null) {
                        setNext(result);
                        this.nextCreated = true;
                    }
                }
            }
        }

        return result;
    }

    /**
     * Returns the callback invoked on response reception. If the value is not
     * null, then the associated request will be executed asynchronously.
     *
     * @return The callback invoked on response reception.
     */
    public Uniform getOnResponse() {
        return getRequest().getOnResponse();
    }

    /**
     * Returns the callback invoked after sending the request.
     *
     * @return The callback invoked after sending the request.
     */
    public Uniform getOnSent() {
        return getRequest().getOnSent();
    }

    /**
     * Returns the parent resource. The parent resource is defined in the sense
     * of hierarchical URIs. If the resource URI is not hierarchical, then an
     * exception is thrown.
     *
     * @return The parent resource.
     */
    public ClientResource getParent() throws ResourceException {
        ClientResource result = null;

        if (getReference().isHierarchical()) {
            result = new ClientResource(this);
            result.setReference(getReference().getParentRef());
        } else {
            doError(Status.CLIENT_ERROR_BAD_REQUEST,
                    "The resource URI is not hierarchical.");
        }

        return result;
    }


    /**
     * Returns the number of retry attempts before reporting an error. Default
     * value is 2.
     *
     * @return The number of retry attempts before reporting an error.
     */
    public int getRetryAttempts() {
        return retryAttempts;
    }

    /**
     * Returns the delay in milliseconds between two retry attempts. Default
     * value is 2 seconds.
     *
     * @return The delay in milliseconds between two retry attempts.
     */
    public long getRetryDelay() {
        return retryDelay;
    }

    /**
     * Handles the call by invoking the next handler. The prototype request is
     * retrieved via {@link #getRequest()} and cloned and the response is set as
     * the latest with {@link #setResponse(Response)}. If necessary the
     * {@link #setNext(Uniform)} method is called as well with a {@link Client}
     * instance matching the request protocol.
     *
     * @return The optional response entity.
     * @see #getNext()
     */
    @Override
    public Representation handle() {
        Response response = handleOutbound(new Request(getRequest()));
        return (response == null) ? null : response.getEntity();
    }

    /**
     * Handles the call by cloning the prototype request, setting the method and
     * entity.
     *
     * @param method
     *            The request method to use.
     * @return The optional response entity.
     */
    protected Representation handle(Method method) {
        return handle(method, (Representation) null);
    }


    /**
     * Handles the call by cloning the prototype request, setting the method and
     * entity.
     *
     * @param method
     *            The request method to use.
     * @param mediaType
     *            The preferred result media type.
     * @return The optional response entity.
     */
    protected Representation handle(Method method, MediaType mediaType) {
        return handle(method, (Representation) null, mediaType);
    }


    /**
     * Handles the call by cloning the prototype request, setting the method and
     * entity.
     *
     * @param method
     *            The request method to use.
     * @param entity
     *            The request entity to set.
     * @return The optional response entity.
     */
    protected Representation handle(Method method, Representation entity) {
        Request request = createRequest();
        request.setMethod(method);
        request.setEntity(entity);
        return handle(method, entity, getClientInfo());
    }

    /**
     * Handles the call by cloning the prototype request, setting the method and
     * entity.
     *
     * @param method
     *            The request method to use.
     * @param entity
     *            The request entity to set.
     * @param clientInfo
     *            The client preferences.
     * @return The optional response entity.
     */
    protected Representation handle(Method method, Representation entity,
            ClientInfo clientInfo) {
        // Prepare the request by cloning the prototype request
        Request request = createRequest();
        request.setMethod(method);
        request.setEntity(entity);
        request.setClientInfo(clientInfo);

        // Actually handle the call
        Response response = handleOutbound(request);
        return handleInbound(response);
    }

    /**
     * Handles the call by cloning the prototype request, setting the method and
     * entity.
     *
     * @param method
     *            The request method to use.
     * @param entity
     *            The request entity to set.
     * @param mediaType
     *            The preferred result media type.
     * @return The optional response entity.
     */
    protected Representation handle(Method method, Representation entity,
            MediaType mediaType) {
        return handle(method, entity, new ClientInfo(mediaType));
    }

    /**
     * Handles the call by invoking the next handler. Then a new response is
     * created and the {@link #handle(Request, Response, List, int, Uniform)}
     * method is invoked and the response set as the latest response with
     * {@link #setResponse(Response)}.
     *
     * @param request
     *            The request to handle.
     * @return The response created.
     * @see #getNext()
     * @deprecated Use the {@link #handleOutbound(Request)} method instead
     */
    @Deprecated
    public Response handle(Request request) {
        return handleOutbound(request);
    }

    /**
     * Handle the call and follow redirection for safe methods.
     *
     * @param request
     *            The request to send.
     * @param response
     *            The response to update.
     * @param references
     *            The references that caused a redirection to prevent infinite
     *            loops.
     * @param retryAttempt
     *            The number of remaining attempts.
     * @param next
     *            The next handler handling the call.
     */
    protected void handle(Request request, Response response,
            List<Reference> references, int retryAttempt, Uniform next) {
        if (next != null) {

            // Actually handle the call
            next.handle(request, response);

            // Check for redirections
            if (isFollowingRedirects() && response.getStatus().isRedirection()
                    && (response.getLocationRef() != null)) {
                boolean doRedirection = false;

                if (request.getMethod().isSafe()) {
                    doRedirection = true;
                } else {
                    if (Status.REDIRECTION_SEE_OTHER.equals(response
                            .getStatus())) {
                        // The user agent is redirected using the GET method
                        request.setMethod(Method.GET);
                        request.setEntity(null);
                        doRedirection = true;
                    } else if (Status.REDIRECTION_USE_PROXY.equals(response
                            .getStatus())) {
                        doRedirection = true;
                    }
                }

                if (doRedirection) {
                    redirect(request, response, references, retryAttempt, next);
                } else {
                    getLogger().fine(
                            "Unable to redirect the client call after a response"
                                    + response);
                }
            } else if (isRetryOnError()
                    && response.getStatus().isRecoverableError()
                    && request.getMethod().isIdempotent()
                    && (retryAttempt < getRetryAttempts())
                    && ((request.getEntity() == null) || request.getEntity()
                            .isAvailable())) {
                retry(request, response, references, retryAttempt, next);
            }

        } else {
            getLogger().log(Level.WARNING,
                    "Request ignored as no next Restlet is available");
        }
    }

    /**
     * Handles the inbound call. Note that only synchronous calls are processed.
     *
     * @param response
     * @return The response's entity, if any.
     */
    public Representation handleInbound(Response response) {
        Representation result = null;

        // Verify that the request was synchronous
        if (response.getRequest().isSynchronous()) {
            if (response.getStatus().isError()) {
                doError(response.getStatus());
            } else {
                result = (response == null) ? null : response.getEntity();
            }
        }

        return result;
    }

    /**
     * Handles the outbound call by invoking the next handler.
     *
     * @param request
     *            The request to handle.
     * @return The response created.
     * @see #getNext()
     */
    public Response handleOutbound(Request request) {
        Response response = createResponse(request);
        Uniform next = getNext();

        if (next != null) {
            // Effectively handle the call
            handle(request, response, null, 0, next);

            // Update the last received response.
            setResponse(response);
        } else {
            getLogger()
                    .warning(
                            "Unable to process the call for a client resource. No next Restlet has been provided.");
        }

        return response;
    }

    /**
     * Indicates if there is a next Restlet.
     *
     * @return True if there is a next Restlet.
     */
    public boolean hasNext() {
        return getNext() != null;
    }

    /**
     * Represents the resource using content negotiation to select the best
     * variant based on the client preferences. This method is identical to
     * {@link #get()} but doesn't return the actual content of the
     * representation, only its metadata.<br>
     * <br>
     * Note that the client preferences will be automatically adjusted, but only
     * for this request. If you want to change them once for all, you can use
     * the {@link #getClientInfo()} method.<br>
     * <br>
     * If a success status is not returned, then a resource exception is thrown.
     *
     * @return The best representation.
     * @throws ResourceException
     * @see <a
     *      href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.4">HTTP
     *      HEAD method</a>
     */
    public Representation head() throws ResourceException {
        return handle(Method.HEAD);
    }

    /**
     * Represents the resource using a given media type. This method is
     * identical to {@link #get(MediaType)} but doesn't return the actual
     * content of the representation, only its metadata.<br>
     * <br>
     * Note that the client preferences will be automatically adjusted, but only
     * for this request. If you want to change them once for all, you can use
     * the {@link #getClientInfo()} method.<br>
     * <br>
     * If a success status is not returned, then a resource exception is thrown.
     *
     * @param mediaType
     *            The media type of the representation to retrieve.
     * @return The representation matching the given media type.
     * @throws ResourceException
     * @see <a
     *      href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.4">HTTP
     *      HEAD method</a>
     */
    public Representation head(MediaType mediaType) throws ResourceException {
        return handle(Method.HEAD, mediaType);
    }

    /**
     * Indicates if redirections are followed.
     *
     * @return True if redirections are followed.
     */
    public boolean isFollowingRedirects() {
        return followingRedirects;
    }



    /**
     * Indicates if idempotent requests should be retried on error. Default
     * value is true.
     *
     * @return True if idempotent requests should be retried on error.
     */
    public boolean isRetryOnError() {
        return retryOnError;
    }

    /**
     * Describes the resource using content negotiation to select the best
     * variant based on the client preferences. If a success status is not
     * returned, then a resource exception is thrown.
     *
     * @return The best description.
     * @throws ResourceException
     * @see <a
     *      href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.2">HTTP
     *      OPTIONS method</a>
     */
    public Representation options() throws ResourceException {
        return handle(Method.OPTIONS);
    }


    /**
     * Describes the resource using a given media type. If a success status is
     * not returned, then a resource exception is thrown.
     *
     * @param mediaType
     *            The media type of the representation to retrieve.
     * @return The matched description or null.
     * @throws ResourceException
     * @see <a
     *      href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.2">HTTP
     *      OPTIONS method</a>
     */
    public Representation options(MediaType mediaType) throws ResourceException {
        return handle(Method.OPTIONS, mediaType);
    }

    /**
     * Posts an object entity. Automatically serializes the object using the
     * {@link org.restlet.client.service.ConverterService}.
     *
     * @param entity
     *            The object entity to post.
     * @return The optional result entity.
     * @throws ResourceException
     * @see <a
     *      href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.5">HTTP
     *      POST method</a>
     */
    public Representation post(Object entity) throws ResourceException {
        return post(toRepresentation(entity, null));
    }


    /**
     * Posts an object entity. Automatically serializes the object using the
     * {@link org.restlet.client.service.ConverterService}.
     *
     * @param entity
     *            The object entity to post.
     * @param mediaType
     *            The media type of the representation to retrieve.
     * @return The response object entity.
     * @throws ResourceException
     * @see <a
     *      href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.5">HTTP
     *      POST method</a>
     */
    public Representation post(Object entity, MediaType mediaType)
            throws ResourceException {
        return handle(Method.POST, toRepresentation(entity, null), mediaType);
    }

    /**
     * Posts a representation. If a success status is not returned, then a
     * resource exception is thrown.
     *
     * @param entity
     *            The posted entity.
     * @return The optional result entity.
     * @throws ResourceException
     * @see <a
     *      href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.5">HTTP
     *      POST method</a>
     */
    public Representation post(Representation entity) throws ResourceException {
        return handle(Method.POST, entity);
    }

    /**
     * Puts an object entity. Automatically serializes the object using the
     * {@link org.restlet.client.service.ConverterService}.
     *
     * @param entity
     *            The object entity to put.
     * @return The optional result entity.
     * @throws ResourceException
     * @see <a
     *      href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.6">HTTP
     *      PUT method</a>
     */
    public Representation put(Object entity) throws ResourceException {
        return put(toRepresentation(entity, null));
    }


    /**
     * Puts an object entity. Automatically serializes the object using the
     * {@link org.restlet.client.service.ConverterService}.
     *
     * @param entity
     *            The object entity to post.
     * @param mediaType
     *            The media type of the representation to retrieve.
     * @return The response object entity.
     * @throws ResourceException
     * @see <a
     *      href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.6">HTTP
     *      PUT method</a>
     */
    public Representation put(Object entity, MediaType mediaType)
            throws ResourceException {
        return handle(Method.PUT, toRepresentation(entity, null), mediaType);
    }

    /**
     * Creates or updates a resource with the given representation as new state
     * to be stored. If a success status is not returned, then a resource
     * exception is thrown.
     *
     * @param entity
     *            The request entity to store.
     * @return The optional result entity.
     * @throws ResourceException
     * @see <a
     *      href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.6">HTTP
     *      PUT method</a>
     */
    public Representation put(Representation entity) throws ResourceException {
        return handle(Method.PUT, entity);
    }

    /**
     * Effectively redirects a client call. By default, it checks for infinite
     * loops and unavailable entities, the references list is updated and the
     * {@link #handle(Request, Response, List, int, Uniform)} method invoked.
     *
     * @param request
     *            The request to send.
     * @param response
     *            The response to update.
     * @param references
     *            The references that caused a redirection to prevent infinite
     *            loops.
     * @param retryAttempt
     *            The number of remaining attempts.
     * @param next
     *            The next handler handling the call.
     */
    protected void redirect(Request request, Response response,
            List<Reference> references, int retryAttempt, Uniform next) {
        Reference newTargetRef = response.getLocationRef();

        if ((references != null) && references.contains(newTargetRef)) {
            getLogger().warning(
                    "Infinite redirection loop detected with URI: "
                            + newTargetRef);
        } else if (request.getEntity() != null && !request.isEntityAvailable()) {
            getLogger()
                    .warning(
                            "Unable to follow the redirection because the request entity isn't available anymore.");
        } else {
            if (references == null) {
                references = new ArrayList<Reference>();
            }

            if (references.size() >= getMaxRedirects()) {
                getLogger()
                        .warning(
                                "Unable to follow the redirection because the request the maximum number of redirections for a single call has been reached.");
            } else {
                // Add to the list of redirection reference
                // to prevent infinite loops
                references.add(request.getResourceRef());
                request.setResourceRef(newTargetRef);
                handle(request, response, references, 0, next);
            }
        }
    }

    /**
     * Effectively retries a failed client call. By default, it sleeps before
     * the retry attempt and increments the number of retries.
     *
     * @param request
     *            The request to send.
     * @param response
     *            The response to update.
     * @param references
     *            The references that caused a redirection to prevent infinite
     *            loops.
     * @param retryAttempt
     *            The number of remaining attempts.
     * @param next
     *            The next handler handling the call.
     */
    protected void retry(Request request, Response response,
            List<Reference> references, int retryAttempt, Uniform next) {
        getLogger().log(
                Level.INFO,
                "A recoverable error was detected ("
                        + response.getStatus().getCode()
                        + "), attempting again in " + getRetryDelay() + " ms.");

        // Wait before attempting again
        if (getRetryDelay() > 0) {
             com.google.gwt.user.client.Timer timer = new
             com.google.gwt.user.client.Timer() {
             public void run() {}
             };
             timer.schedule((int) getRetryDelay());
        }

        // Retry the call
        handle(request, response, references, ++retryAttempt, next);
    }

    /**
     * Sets the request attribute value.
     *
     * @param name
     *            The attribute name.
     * @param value
     *            The attribute to set.
     */
    public void setAttribute(String name, Object value) {
        getRequestAttributes().put(name, value);
    }

    /**
     * Sets the authentication response sent by a client to an origin server.
     *
     * @param challengeResponse
     *            The authentication response sent by a client to an origin
     *            server.
     * @see Request#setChallengeResponse(ChallengeResponse)
     */
    public void setChallengeResponse(ChallengeResponse challengeResponse) {
        getRequest().setChallengeResponse(challengeResponse);
    }

    /**
     * Sets the authentication response sent by a client to an origin server
     * given a scheme, identifier and secret.
     *
     * @param scheme
     *            The challenge scheme.
     * @param identifier
     *            The user identifier, such as a login name or an access key.
     * @param secret
     *            The user secret, such as a password or a secret key.
     */
    public void setChallengeResponse(ChallengeScheme scheme,
            final String identifier, String secret) {
        setChallengeResponse(new ChallengeResponse(scheme, identifier, secret));
    }



    /**
     * Sets the client-specific information.
     *
     * @param clientInfo
     *            The client-specific information.
     * @see Request#setClientInfo(ClientInfo)
     */
    public void setClientInfo(ClientInfo clientInfo) {
        getRequest().setClientInfo(clientInfo);
    }

    /**
     * Sets the conditions applying to this request.
     *
     * @param conditions
     *            The conditions applying to this request.
     * @see Request#setConditions(Conditions)
     */
    public void setConditions(Conditions conditions) {
        getRequest().setConditions(conditions);
    }

    /**
     * Sets the cookies provided by the client.
     *
     * @param cookies
     *            The cookies provided by the client.
     * @see Request#setCookies(Series)
     */
    public void setCookies(Series<Cookie> cookies) {
        getRequest().setCookies(cookies);
    }


    /**
     * Indicates if redirections are followed.
     *
     * @param followingRedirects
     *            True if redirections are followed.
     */
    public void setFollowingRedirects(boolean followingRedirects) {
        this.followingRedirects = followingRedirects;
    }

    /**
     * Sets the host reference.
     *
     * @param hostRef
     *            The host reference.
     * @see Request#setHostRef(Reference)
     */
    public void setHostRef(Reference hostRef) {
        getRequest().setHostRef(hostRef);
    }

    /**
     * Sets the host reference using an URI string.
     *
     * @param hostUri
     *            The host URI.
     * @see Request#setHostRef(String)
     */
    public void setHostRef(String hostUri) {
        getRequest().setHostRef(hostUri);
    }

    /**
     * Indicates if the call is loggable
     *
     * @param loggable
     *            True if the call is loggable
     */
    public void setLoggable(boolean loggable) {
        getRequest().setLoggable(loggable);
    }

    /**
     * Sets the maximum number of redirections that can be automatically
     * followed for a single call.
     *
     * @param maxRedirects
     *            The maximum number of redirections that can be automatically
     *            followed for a single call.
     */
    public void setMaxRedirects(int maxRedirects) {
        this.maxRedirects = maxRedirects;
    }

    /**
     * Sets the method called.
     *
     * @param method
     *            The method called.
     * @see Request#setMethod(Method)
     */
    public void setMethod(Method method) {
        getRequest().setMethod(method);
    }

    /**
     * Sets the next handler such as a Restlet or a Filter.
     *
     * In addition, this method will set the context of the next Restlet if it
     * is null by passing a reference to its own context.
     *
     * @param next
     *            The next handler.
     */
    public void setNext(org.restlet.client.Uniform next) {
        if (next instanceof Restlet) {
            Restlet nextRestlet = (Restlet) next;

            if (nextRestlet.getContext() == null) {
                nextRestlet.setContext(getContext());
            }
        }

        this.next = next;

        // If true, it must be updated after calling this method
        this.nextCreated = false;
    }

    /**
     * Sets the callback invoked on response reception. If the value is not
     * null, then the associated request will be executed asynchronously.
     *
     * @param onResponseCallback
     *            The callback invoked on response reception.
     */
    public void setOnResponse(Uniform onResponseCallback) {
        getRequest().setOnResponse(onResponseCallback);
    }

    /**
     * Sets the callback invoked after sending the request.
     *
     * @param onSentCallback
     *            The callback invoked after sending the request.
     */
    public void setOnSent(Uniform onSentCallback) {
        getRequest().setOnSent(onSentCallback);
    }

    /**
     * Sets the original reference requested by the client.
     *
     * @param originalRef
     *            The original reference.
     * @see Request#setOriginalRef(Reference)
     */
    public void setOriginalRef(Reference originalRef) {
        getRequest().setOriginalRef(originalRef);
    }

    /**
     * Sets the protocol used or to be used.
     *
     * @param protocol
     *            The protocol used or to be used.
     */
    public void setProtocol(Protocol protocol) {
        getRequest().setProtocol(protocol);
    }

    /**
     * Sets the ranges to return from the target resource's representation.
     *
     * @param ranges
     *            The ranges.
     * @see Request#setRanges(List)
     */
    public void setRanges(List<Range> ranges) {
        getRequest().setRanges(ranges);
    }

    /**
     * Sets the resource's reference. If the reference is relative, it will be
     * resolved as an absolute reference. Also, the context's base reference
     * will be reset. Finally, the reference will be normalized to ensure a
     * consistent handling of the call.
     *
     * @param reference
     *            The resource reference.
     * @see Request#setResourceRef(Reference)
     */
    public void setReference(Reference reference) {
        getRequest().setResourceRef(reference);
    }

    /**
     * Sets the resource's reference using an URI string. Note that the URI can
     * be either absolute or relative to the context's base reference.
     *
     * @param uri
     *            The resource URI.
     * @see Request#setResourceRef(String)
     */
    public void setReference(String uri) {
        getRequest().setResourceRef(uri);
    }

    /**
     * Sets the referrer reference if available.
     *
     * @param referrerRef
     *            The referrer reference.
     * @see Request#setReferrerRef(Reference)
     */
    public void setReferrerRef(Reference referrerRef) {
        getRequest().setReferrerRef(referrerRef);
    }

    /**
     * Sets the referrer reference if available using an URI string.
     *
     * @param referrerUri
     *            The referrer URI.
     * @see Request#setReferrerRef(String)
     */
    public void setReferrerRef(String referrerUri) {
        getRequest().setReferrerRef(referrerUri);
    }



    /**
     * Sets the number of retry attempts before reporting an error.
     *
     * @param retryAttempts
     *            The number of retry attempts before reporting an error.
     */
    public void setRetryAttempts(int retryAttempts) {
        this.retryAttempts = retryAttempts;
    }

    /**
     * Sets the delay in milliseconds between two retry attempts. The default
     * value is two seconds.
     *
     * @param retryDelay
     *            The delay in milliseconds between two retry attempts.
     */
    public void setRetryDelay(long retryDelay) {
        this.retryDelay = retryDelay;
    }

    /**
     * Indicates if idempotent requests should be retried on error.
     *
     * @param retryOnError
     *            True if idempotent requests should be retried on error.
     */
    public void setRetryOnError(boolean retryOnError) {
        this.retryOnError = retryOnError;
    }

}
TOP

Related Classes of org.restlet.client.resource.ClientResource

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.