Package com.jayway.jaxrs.hateoas.core

Source Code of com.jayway.jaxrs.hateoas.core.HateoasResponseBuilderImpl$FixedLinkProducer

/*
* Copyright 2011 the original author or authors.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*       http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jayway.jaxrs.hateoas.core;

import com.jayway.jaxrs.hateoas.*;
import com.jayway.jaxrs.hateoas.core.HateoasResponse.HateoasResponseBuilder;
import com.jayway.jaxrs.hateoas.support.AtomRels;
import com.jayway.jaxrs.hateoas.support.FieldPath;
import com.jayway.jaxrs.hateoas.support.ReflectionUtils;
import com.jayway.jaxrs.hateoas.web.RequestContext;
import com.sun.jersey.core.header.OutBoundHeaders;
import com.sun.jersey.core.spi.factory.ResponseImpl;

import javax.ws.rs.core.*;
import java.lang.reflect.Type;
import java.net.URI;
import java.util.*;
import java.util.Map.Entry;

/**
* Default implementation of {@link HateoasResponseBuilder}.
*
* @author Mattias Hellborg Arthursson
* @author Kalle Stenflo
*/
public class HateoasResponseBuilderImpl extends HateoasResponse.HateoasResponseBuilder {

    private Response.StatusType statusType = Response.Status.NO_CONTENT;

    private OutBoundHeaders headers;

    private Object entity;

    private Type entityType;

    private final Map<FieldPath, ChainedLinkProducer> linkMappings = new HashMap<FieldPath, ChainedLinkProducer>();

    @Override
    public HateoasResponseBuilder link(String id, String rel, Object... params) {
        return links(HateoasResponseBuilder.makeLink(id, rel, params));
    }

    @Override
    public HateoasResponseBuilder link(FieldPath fieldPath, String id, String rel, String... entityFields) {
        return link(fieldPath, new ReflectionBasedLinkProducer(id, rel, entityFields));
    }

    @Override
    public HateoasResponseBuilder selfLink(FieldPath fieldPath, String id, String... entityFields) {
        return link(fieldPath, id, AtomRels.SELF, entityFields);
    }

    @Override
    public HateoasResponseBuilder link(FieldPath fieldPath, LinkProducer<?> linkProducer) {
        if (!linkMappings.containsKey(fieldPath)) {
            linkMappings.put(fieldPath, new ChainedLinkProducer());
        }

        ChainedLinkProducer chainedLinkProducer = linkMappings.get(fieldPath);
        chainedLinkProducer.append(linkProducer);

        return this;
    }

    @Override
    public HateoasResponseBuilder selfLink(String id, Object... params) {
        return link(id, AtomRels.SELF, params);
    }


    @Override
    public HateoasResponseBuilder each(String id, String rel, String... entityFields) {
        return each(new ReflectionBasedLinkProducer(id, rel, entityFields));
    }

    @Override
    public HateoasResponseBuilder selfEach(String id, String... entityFields) {
        return each(id, AtomRels.SELF, entityFields);
    }

    @Override
    public HateoasResponse.HateoasResponseBuilder links(HateoasLink... links) {
        return link(FieldPath.EMPTY_PATH, new FixedLinkProducer(Arrays.asList(links)));
    }

    @Override
    public HateoasResponseBuilder each(LinkProducer<?> linkProducer) {
        CollectionWrapperStrategy collectionWrapperStrategy = HateoasResponseBuilder.getCollectionWrapperStrategy();
        return link(FieldPath.path(collectionWrapperStrategy.rowsFieldName()), linkProducer);
    }

    //-------------------------


    @Override
    public HateoasResponseBuilder link(FieldPath fieldPath, String id, String rel, ParamExpander... paramExpanders) {
        return link(fieldPath, new ParamExpandingLinkProducer(id, rel, paramExpanders));
    }

    @Override
    public HateoasResponseBuilder selfLink(FieldPath fieldPath, String id, ParamExpander... paramExpanders) {
        return link(fieldPath, id, AtomRels.SELF, paramExpanders);
    }

    @Override
    public HateoasResponseBuilder selfLink(String id, ParamExpander... paramExpanders) {
        return link(id, AtomRels.SELF, paramExpanders);
    }

    @Override
    public HateoasResponseBuilder link(String id, String rel, ParamExpander... paramExpanders) {

        ParamExpandingLinkProducer linkProducer = new ParamExpandingLinkProducer(id, rel, paramExpanders);

        return links(linkProducer.getLinks(entity).toArray(new HateoasLink[0]));
    }

    @Override
    public HateoasResponseBuilder each(String id, String rel, ParamExpander... paramExpanders) {
        return each(new ParamExpandingLinkProducer(id, rel, paramExpanders));
    }

    @Override
    public HateoasResponseBuilder selfEach(String id, ParamExpander... paramExpanders) {
        return each(id, AtomRels.SELF, paramExpanders);
    }


    //-------------------------


    public HateoasResponseBuilderImpl() {
    }

    private HateoasResponseBuilderImpl(HateoasResponseBuilderImpl that) {
        this.statusType = that.statusType;
        this.entity = that.entity;
        if (that.headers != null) {
            this.headers = new OutBoundHeaders(that.headers);
        } else {
            this.headers = null;
        }
        this.entityType = that.entityType;
    }

    public HateoasResponse.HateoasResponseBuilder entityWithType(Object entity,
                                                                 Type entityType) {
        this.entity = entity;
        this.entityType = entityType;
        return this;
    }

    private OutBoundHeaders getHeaders() {
        if (headers == null)
            headers = new OutBoundHeaders();
        return headers;
    }

    // Response.Builder

    @SuppressWarnings("unchecked")
    public HateoasResponse build() {
        HateoasLinkInjector<Object> linkInjector = HateoasResponseBuilder.getLinkInjector();

        CollectionWrapperStrategy collectionWrapperStrategy = HateoasResponseBuilder.getCollectionWrapperStrategy();
        HateoasVerbosity verbosity = HateoasVerbosity.valueOf(RequestContext.getRequestContext().getVerbosityHeader());

        Object newEntity = entity;
        if (entity != null) {
            if (Collection.class.isAssignableFrom(entity.getClass())) {
                newEntity = collectionWrapperStrategy.wrapRootCollection((Collection<Object>) entity);
            }

            Set<Entry<FieldPath, ChainedLinkProducer>> entries = linkMappings.entrySet();
            for (Entry<FieldPath, ChainedLinkProducer> entry : entries) {
                newEntity = entry.getKey().injectLinks(newEntity, linkInjector, entry.getValue(), verbosity);
            }
        }

        final HateoasResponse r = new HateoasResponseImpl(statusType,
                getHeaders(), newEntity, entityType);
        reset();
        return r;
    }

    public HateoasResponse render(String template) {
        HateoasLinkInjector<Object> linkInjector = HateoasResponseBuilder.getLinkInjector();

        CollectionWrapperStrategy collectionWrapperStrategy = HateoasResponseBuilder.getCollectionWrapperStrategy();
        HateoasVerbosity verbosity = HateoasVerbosity.valueOf(RequestContext.getRequestContext().getVerbosityHeader());

        Object newEntity = entity;
        if (entity != null) {
            if (Collection.class.isAssignableFrom(entity.getClass())) {
                newEntity = collectionWrapperStrategy.wrapRootCollection((Collection<Object>) entity);
            }

            Set<Entry<FieldPath, ChainedLinkProducer>> entries = linkMappings.entrySet();
            for (Entry<FieldPath, ChainedLinkProducer> entry : entries) {
                Object oldEntity = newEntity;
                newEntity = entry.getKey().injectLinks(newEntity, linkInjector, entry.getValue(), verbosity);
                Object postEntity = newEntity;
            }
        }

        final HateoasResponse r = new HateoasResponseImpl(statusType, getHeaders(), HateoasResponseBuilder.getViewFactory().createView(template, newEntity), entityType);
        reset();
        return r;
    }

    private void reset() {
        statusType = Response.Status.NO_CONTENT;
        headers = null;
        entity = null;
        entityType = null;
        linkMappings.clear();
    }

    @Override
    public HateoasResponse.HateoasResponseBuilder clone() {
        return new HateoasResponseBuilderImpl(this);
    }

    public HateoasResponse.HateoasResponseBuilder status(
            Response.StatusType status) {
        if (status == null)
            throw new IllegalArgumentException();
        this.statusType = status;
        return this;
    }

    ;

    public HateoasResponse.HateoasResponseBuilder status(int status) {
        return status(ResponseImpl.toStatusType(status));
    }

    public HateoasResponse.HateoasResponseBuilder entity(Object entity) {
        this.entity = entity;
        this.entityType = (entity != null) ? entity.getClass() : null;
        return this;
    }

    public HateoasResponse.HateoasResponseBuilder type(MediaType type) {
        headerSingle(HttpHeaders.CONTENT_TYPE, type);
        return this;
    }

    public HateoasResponse.HateoasResponseBuilder type(String type) {
        return type(type == null ? null : MediaType.valueOf(type));
    }

    public HateoasResponse.HateoasResponseBuilder variant(Variant variant) {
        if (variant == null) {
            type((MediaType) null);
            language((String) null);
            encoding(null);
            return this;
        }

        type(variant.getMediaType());
        // TODO set charset
        language(variant.getLanguage());
        encoding(variant.getEncoding());

        return this;
    }

    public HateoasResponse.HateoasResponseBuilder variants(
            List<Variant> variants) {
        if (variants == null) {
            header(HttpHeaders.VARY, null);
            return this;
        }

        if (variants.isEmpty())
            return this;

        MediaType accept = variants.get(0).getMediaType();
        boolean vAccept = false;

        Locale acceptLanguage = variants.get(0).getLanguage();
        boolean vAcceptLanguage = false;

        String acceptEncoding = variants.get(0).getEncoding();
        boolean vAcceptEncoding = false;

        for (Variant v : variants) {
            vAccept |= !vAccept && vary(v.getMediaType(), accept);
            vAcceptLanguage |= !vAcceptLanguage
                    && vary(v.getLanguage(), acceptLanguage);
            vAcceptEncoding |= !vAcceptEncoding
                    && vary(v.getEncoding(), acceptEncoding);
        }

        StringBuilder vary = new StringBuilder();
        append(vary, vAccept, HttpHeaders.ACCEPT);
        append(vary, vAcceptLanguage, HttpHeaders.ACCEPT_LANGUAGE);
        append(vary, vAcceptEncoding, HttpHeaders.ACCEPT_ENCODING);

        if (vary.length() > 0)
            header(HttpHeaders.VARY, vary.toString());
        return this;
    }

    private boolean vary(MediaType v, MediaType vary) {
        return v != null && !v.equals(vary);
    }

    private boolean vary(Locale v, Locale vary) {
        return v != null && !v.equals(vary);
    }

    private boolean vary(String v, String vary) {
        return v != null && !v.equalsIgnoreCase(vary);
    }

    private void append(StringBuilder sb, boolean v, String s) {
        if (v) {
            if (sb.length() > 0)
                sb.append(',');
            sb.append(s);
        }
    }

    public HateoasResponse.HateoasResponseBuilder language(String language) {
        headerSingle(HttpHeaders.CONTENT_LANGUAGE, language);
        return this;
    }

    public HateoasResponse.HateoasResponseBuilder language(Locale language) {
        headerSingle(HttpHeaders.CONTENT_LANGUAGE, language);
        return this;
    }

    public HateoasResponse.HateoasResponseBuilder location(URI location) {
        headerSingle(HttpHeaders.LOCATION, location);
        return this;
    }

    public HateoasResponse.HateoasResponseBuilder location(HateoasLink location) {
        headerSingle(HttpHeaders.LOCATION, location.getHref());
        return this;
    }

    public HateoasResponse.HateoasResponseBuilder contentLocation(URI location) {
        headerSingle(HttpHeaders.CONTENT_LOCATION, location);
        return this;
    }

    public Response.ResponseBuilder encoding(String encoding) {
        headerSingle(HttpHeaders.CONTENT_ENCODING, encoding);
        return this;
    }

    public HateoasResponse.HateoasResponseBuilder tag(EntityTag tag) {
        headerSingle(HttpHeaders.ETAG, tag);
        return this;
    }

    public HateoasResponse.HateoasResponseBuilder tag(String tag) {
        return tag(tag == null ? null : new EntityTag(tag));
    }

    public HateoasResponse.HateoasResponseBuilder lastModified(Date lastModified) {
        headerSingle(HttpHeaders.LAST_MODIFIED, lastModified);
        return this;
    }

    public HateoasResponse.HateoasResponseBuilder cacheControl(
            CacheControl cacheControl) {
        headerSingle(HttpHeaders.CACHE_CONTROL, cacheControl);
        return this;
    }

    public HateoasResponse.HateoasResponseBuilder expires(Date expires) {
        headerSingle(HttpHeaders.EXPIRES, expires);
        return this;
    }

    public HateoasResponse.HateoasResponseBuilder cookie(NewCookie... cookies) {
        if (cookies != null) {
            for (NewCookie cookie : cookies)
                header(HttpHeaders.SET_COOKIE, cookie);
        } else {
            header(HttpHeaders.SET_COOKIE, null);
        }
        return this;
    }

    public HateoasResponse.HateoasResponseBuilder header(String name,
                                                         Object value) {
        return header(name, value, false);
    }

    public HateoasResponse.HateoasResponseBuilder headerSingle(String name,
                                                               Object value) {
        return header(name, value, true);
    }

    public HateoasResponse.HateoasResponseBuilder header(String name,
                                                         Object value, boolean single) {
        if (value != null) {
            if (single) {
                getHeaders().putSingle(name, value);
            } else {
                getHeaders().add(name, value);
            }
        } else {
            getHeaders().remove(name);
        }
        return this;
    }

    private final static class ParamExpandingLinkProducer implements LinkProducer<Object> {

        private final String id;
        private final String rel;
        private final ParamExpander[] paramExpanders;

        private ParamExpandingLinkProducer(String id, String rel, ParamExpander... paramExpanders) {
            this.id = id;
            this.rel = rel;
            this.paramExpanders = paramExpanders;
        }

        @Override
        public Collection<HateoasLink> getLinks(Object entity) {
            Map<String, Object> queryParams = new LinkedHashMap<String, Object>();

            LinkedList<Object> argumentList = new LinkedList<Object>();

            for (ParamExpander paramExpander : paramExpanders) {

                if (paramExpander instanceof ParamExpander.QueryParamExpander) {
                    ParamExpander.QueryParamExpander expander = (ParamExpander.QueryParamExpander) paramExpander;
                    queryParams.put(expander.getName(), expander.getValue());

                } else if (paramExpander instanceof ParamExpander.ReflectionPathParamExpander) {

                    ParamExpander.ReflectionPathParamExpander expander = (ParamExpander.ReflectionPathParamExpander) paramExpander;
                    Object fieldValue = ReflectionUtils.getFieldValueHierarchical(entity, expander.getField());
                    argumentList.add(fieldValue);

                } else if (paramExpander instanceof ParamExpander.PathParamExpander) {

                    ParamExpander.PathParamExpander expander = (ParamExpander.PathParamExpander) paramExpander;
                    argumentList.add(expander.getValue());

                }
            }
            return Collections.singletonList(makeLink(id, rel, queryParams, argumentList.toArray()));
        }
    }

    private final static class ReflectionBasedLinkProducer implements LinkProducer<Object> {
        private final String id;
        private final String rel;
        private final String[] entityFields;

        private ReflectionBasedLinkProducer(String id, String rel, String... entityFields) {
            this.id = id;
            this.rel = rel;
            this.entityFields = entityFields;
        }

        @Override
        public Collection<HateoasLink> getLinks(Object entity) {
            LinkedList<Object> argumentList = new LinkedList<Object>();

            for (String fieldName : entityFields) {
                Object fieldValue = ReflectionUtils.getFieldValueHierarchical(entity, fieldName);
                argumentList.add(fieldValue);
            }

            return Collections.singletonList(makeLink(id, rel, argumentList.toArray()));
        }
    }

    private final static class ChainedLinkProducer implements LinkProducer<Object> {
        private final Collection<LinkProducer<Object>> wrappedCallbacks = new LinkedList<LinkProducer<Object>>();

        @SuppressWarnings("unchecked")
        public void append(LinkProducer<?> callback) {
            wrappedCallbacks.add((LinkProducer<Object>) callback);
        }

        @Override
        public Collection<HateoasLink> getLinks(Object entity) {
            Collection<HateoasLink> result = new LinkedList<HateoasLink>();
            for (LinkProducer<Object> callback : wrappedCallbacks) {
                result.addAll(callback.getLinks(entity));
            }

            return result;
        }
    }

    public final static class FixedLinkProducer implements LinkProducer<Object> {
        private Collection<HateoasLink> links;

        public FixedLinkProducer(HateoasLink link) {
            this(Collections.singleton(link));
        }

        public FixedLinkProducer(Collection<HateoasLink> links) {
            this.links = links;
        }

        @Override
        public Collection<HateoasLink> getLinks(Object entity) {
            return links;
        }
    }

}
TOP

Related Classes of com.jayway.jaxrs.hateoas.core.HateoasResponseBuilderImpl$FixedLinkProducer

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.