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

com.mastfrog.webapi.WebCallBuilder Maven / Gradle / Ivy

There is a newer version: 2.9.7
Show newest version
package com.mastfrog.webapi;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.mastfrog.acteur.headers.Method;
import com.mastfrog.giulius.Dependencies;
import com.mastfrog.util.preconditions.ConfigurationError;
import java.util.HashSet;
import java.util.Set;

/**
 * Builds one element of a web api
 *
 * @author Tim Boudreau
 */
public class WebCallBuilder {

    private Enum id;
    private Method method = Method.GET;
    private String path;
    private final Set> requiredTypes = new HashSet<>();
    private boolean authenticationRequired;
    private Decorators decorators = new Decorators();
    private Interpolators interpolators = new Interpolators();
    private boolean stayOpen;
    private boolean hasBody = true;
    private Class interpreter;

    public WebCallBuilder() {
    }

    public WebCallBuilder(Enum id) {
        this.id = id;
    }

    /**
     * Required - set the ID of this call
     *
     * @param id The id
     * @return this
     */
    public WebCallBuilder id(Enum id) {
        this.id = id;
        return this;
    }

    /**
     * Set the HTTP method of this call (by default it is GET).
     *
     * @param method The method
     * @return this
     */
    public WebCallBuilder method(Method method) {
        this.method = method;
        return this;
    }

    /**
     * Required - Set the path template for this call. To do
     * simple substitution, you can delimit templated items with {{ }} and use
     * simple types whose toString() value is substituted in. So if you have a
     * class called
     * UserId whose
     * toString() method returns a useful representation of the ID,
     * then you can have a template that looks like, say,
     * /users/{{userid}}/dostuff and if a UserId is available when
     * the call is invoked, {{userid}} will be replaced. The templated text
     * should be the lower-cased type name of the type.
     *
     * @param path The path
     * @return This
     */
    public WebCallBuilder path(String path) {
        this.path = path;
        return this;
    }

    /**
     * Add a type which is required by something that will construct the call -
     * this might be a constructor argument to a Decorator subclass, or
     * something similer. Use this to ensure types that will be needed when
     * processing calls are bound correctly.
     *
     * @param type
     * @return
     */
    public WebCallBuilder addRequiredType(Class type) {
        requiredTypes.add(type);
        return this;
    }

    public WebCallBuilder addRequiredTypes(Class... types) {
        for (Class type : types) {
            addRequiredType(type);
        }
        return this;
    }

    /**
     * Mark this call as requiring HTTP basic authentication. To use Basic
     * authentication, do this and include a
     * BasicCredentials in the call context.
     *
     * @return
     */
    public WebCallBuilder authenticationRequired() {
        this.authenticationRequired = true;
        return this;
    }

    public WebCallBuilder authenticationRequired(boolean required) {
        this.authenticationRequired = required;
        return this;
    }
    
    /**
     * Add an interpolator which will replace some contents of the API call path
     * based on some object type. The actual interpolator instance will be
     * created on-demand.
     *
     * @param  The object type
     * @param  The interpolator type
     * @param type The object type
     * @param dec The iterpolator type
     * @return This
     */
    public > WebCallBuilder withInterpolator(Class type, Class dec) {
        addRequiredType(type);
        interpolators.add(type, dec);
        return this;
    }

    /**
     * Add a decorator which will somehow modify an HTTP request based on some
     * object passed into the call context.
     *
     * @param  The object type
     * @param  The decorator type
     * @param type The object type
     * @param dec The decorator type
     * @return this
     */
    public > WebCallBuilder withDecorator(Class type, Class dec) {
        addRequiredType(type);
        decorators.add(type, dec);
        return this;
    }

    /**
     * This call utilizes an open HTTP connection - don't close the channel when
     * the request is completed.
     *
     * @return this
     */
    public WebCallBuilder stayOpen() {
        stayOpen = true;
        return this;
    }

    /**
     * Determine whether to expect a response body. If false, the system may opt
     * to close the connection and call the callback as soon as headers have
     * been received.
     *
     * @param val
     * @return
     */
    public WebCallBuilder hasBody(boolean val) {
        this.hasBody = val;
        return this;
    }

    /**
     * Thing which interprets the response
     *
     * @param interp An interpreter
     * @return this
     */
    public WebCallBuilder interpreter(Class interp) {
        this.interpreter = interp;
        return this;
    }

    /**
     * Build a web call
     *
     * @return A web call.
     * @throws ConfigurationError if the id, method or path are not set
     */
    public WebCall build() {
        if (id == null) {
            throw new ConfigurationError("Enum id not set");
        }
        if (method == null) {
            throw new ConfigurationError("Method not set");
        }
        if (path == null) {
            throw new ConfigurationError("Path not set");
        }
        return new WebCallImpl(id, method, path, requiredTypes,
                authenticationRequired, decorators, interpolators, stayOpen,
                /*type,*/ hasBody, interpreter);
    }

    private static class WebCallImpl implements WebCall {

        private final Enum id;
        private final Method method;
        private final String path;
        private final Set> requiredTypes;
        private final boolean authenticationRequired;
        private final Decorators decorators;
        private final Interpolators interpolators;
        private final boolean stayOpen;
        private final boolean hasBody;
        private final Class interpreter;

        public WebCallImpl(Enum id, Method method, String path, Set> requiredTypes, boolean authenticationRequired, Decorators decorators, Interpolators interpolators, boolean stayOpen, /*Class type, */boolean hasBody, Class interpreter) {
            this.id = id;
            this.method = method;
            this.path = path;
            this.requiredTypes = requiredTypes;
            this.authenticationRequired = authenticationRequired;
            this.decorators = decorators;
            this.interpolators = interpolators;
            this.stayOpen = stayOpen;
            this.interpreter = interpreter;
            this.hasBody = hasBody;
        }

        @Override
        public String name() {
            return id.toString();
        }

        @Override
        public Enum id() {
            return id;
        }

        @Override
        public Method method() {
            return method;
        }

        @Override
        public String urlTemplate() {
            return path;
        }

        @Override
        public Class[] requiredTypes() {
            return requiredTypes.toArray(new Class[requiredTypes.size()]);
        }

        @Override
        public boolean authenticationRequired() {
            return authenticationRequired;
        }

        @Override
        public boolean expectResponseBody() {
            return hasBody;
        }

        @Override
        public boolean isStayOpen() {
            return stayOpen;
        }

        @Override
        public > Class decorator(Class type) {
            return decorators.get(type);
        }

        @Override
        public > Class interpolator(Class type) {
            return interpolators.get(type);
        }

        @Override
        public Interpreter interpreter(Dependencies deps) {
            Interpreter result;
            if (interpreter == null || interpreter.equals(DefaultResponseInterceptor.class)) {
                return new DefaultResponseInterceptor(deps.getInstance(ObjectMapper.class));
            } else {
                result = deps.getInstance(interpreter);
            }
            return result;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy