tv.arte.resteventapi.core.presentation.decoration.RestEventApiControllerLinkBuilder.java Source code

Java tutorial

Introduction

Here is the source code for tv.arte.resteventapi.core.presentation.decoration.RestEventApiControllerLinkBuilder.java

Source

package tv.arte.resteventapi.core.presentation.decoration;

/*
 * #%L
 * RestEventAPI
 * %%
 * Copyright (C) 2014 ARTE G.E.I.E
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of The MIT License (MIT) as published by the Open Source 
 * Initiative.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See The 
 * MIT License (MIT) for more details.
 * 
 * You should have received a copy of The MIT License (MIT) 
 * along with this program.  If not, see <http://opensource.org/licenses/MIT>
 * #L%
 */

import java.lang.reflect.Method;
import java.net.URI;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.http.HttpServletRequest;

import org.springframework.core.convert.ConversionService;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.core.LinkBuilderSupport;
import org.springframework.hateoas.core.MappingDiscoverer;
import org.springframework.hateoas.mvc.ControllerLinkBuilder;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
import org.springframework.web.util.UriComponentsBuilder;
import org.springframework.web.util.UriTemplate;

/*
 * Code particialy copied from string-hateoas project
 */

/**
 * Builder to ease building {@link Link} instances pointing to Spring MVC controllers.
 * 
 * @author Oliver Gierke
 * @author Kamill Sokol
 * @author Simeon Petev
 */
public class RestEventApiControllerLinkBuilder extends LinkBuilderSupport<RestEventApiControllerLinkBuilder> {

    private static final MappingDiscoverer DISCOVERER = new RestEventApiAnnotationMappingDiscoverer(
            RequestMapping.class);

    private UriComponentsBuilder uriBuilder;

    /**
     * Creates a new {@link ControllerLinkBuilder} using the given {@link UriComponentsBuilder}.
     * 
     * @param builder must not be {@literal null}.
     */
    protected RestEventApiControllerLinkBuilder(UriComponentsBuilder builder) {
        super(builder);
        this.uriBuilder = builder;
    }

    /*
     * @see org.springframework.hateoas.MethodLinkBuilderFactory#linkTo(Class<?>, Method, Object...)
     */
    public static String linkTo(Class<?> controller, Method method, Map<String, ?> parameters,
            ConversionService conversionService) {

        Assert.notNull(controller, "Controller type must not be null!");
        Assert.notNull(method, "Method must not be null!");

        RestEventApiControllerLinkBuilder linkBuilder = new RestEventApiControllerLinkBuilder(getBuilder());

        if (parameters == null) {
            parameters = new HashMap<String, Object>(1);
        }

        UriTemplate template = new UriTemplate(DISCOVERER.getMapping(controller, method));
        URI uri = template.expand(parameters);
        linkBuilder = linkBuilder.slash(uri);
        List<String> templateVariables = template.getVariableNames();

        for (Entry<String, ?> paramEnt : parameters.entrySet()) {
            if (!templateVariables.contains(paramEnt.getKey())) {
                String queryParamName = paramEnt.getKey();
                Object queryParamValue = null;

                if (paramEnt.getValue() != null) {
                    queryParamValue = conversionService.convert(paramEnt.getValue(), String.class);
                }

                if (queryParamValue != null) {
                    linkBuilder.uriBuilder.queryParam(queryParamName, queryParamValue);
                }
            }
        }

        return linkBuilder.uriBuilder.build().toUriString();
    }

    @Override
    protected RestEventApiControllerLinkBuilder getThis() {
        return this;
    }

    @Override
    protected RestEventApiControllerLinkBuilder createNewInstance(UriComponentsBuilder builder) {
        return new RestEventApiControllerLinkBuilder(builder);
    }

    /**
     * Returns a {@link UriComponentsBuilder} to continue to build the already built URI in a more fine grained way.
     * 
     * @return
     */
    public UriComponentsBuilder toUriComponentsBuilder() {
        return UriComponentsBuilder.fromUri(toUri());
    }

    /**
     * Returns a {@link UriComponentsBuilder} obtained from the current servlet mapping with the host tweaked in case the
     * request contains an {@code X-Forwarded-Host} header and the scheme tweaked in case the request contains an
     * {@code X-Forwarded-Ssl} header
     * 
     * @return
     */
    static UriComponentsBuilder getBuilder() {

        HttpServletRequest request = getCurrentRequest();
        ServletUriComponentsBuilder builder = ServletUriComponentsBuilder.fromServletMapping(request);

        String forwardedSsl = request.getHeader("X-Forwarded-Ssl");

        if (StringUtils.hasText(forwardedSsl) && forwardedSsl.equalsIgnoreCase("on")) {
            builder.scheme("https");
        }

        String host = request.getHeader("X-Forwarded-Host");

        if (!StringUtils.hasText(host)) {
            return builder;
        }

        String[] hosts = StringUtils.commaDelimitedListToStringArray(host);
        String hostToUse = hosts[0];

        if (hostToUse.contains(":")) {

            String[] hostAndPort = StringUtils.split(hostToUse, ":");

            builder.host(hostAndPort[0]);
            builder.port(Integer.parseInt(hostAndPort[1]));

        } else {
            builder.host(hostToUse);
            builder.port(-1); // reset port if it was forwarded from default port
        }

        String port = request.getHeader("X-Forwarded-Port");

        if (StringUtils.hasText(port)) {
            builder.port(Integer.parseInt(port));
        }

        return builder;
    }

    /**
     * Copy of {@link ServletUriComponentsBuilder#getCurrentRequest()} until SPR-10110 gets fixed.
     * 
     * @return
     */
    private static HttpServletRequest getCurrentRequest() {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        Assert.state(requestAttributes != null, "Could not find current request via RequestContextHolder");
        Assert.isInstanceOf(ServletRequestAttributes.class, requestAttributes);
        HttpServletRequest servletRequest = ((ServletRequestAttributes) requestAttributes).getRequest();
        Assert.state(servletRequest != null, "Could not find current HttpServletRequest");
        return servletRequest;
    }
}