Improve request/response holder implementation (#1790)

Make use of RequestContextHolder which provides access to request / response out of the box

Signed-off-by: Marinov Avgustin <Avgustin.Marinov@bosch.com>
This commit is contained in:
Avgustin Marinov
2024-07-29 12:23:06 +03:00
committed by GitHub
parent 9cc9b23398
commit 17432925f9
9 changed files with 36 additions and 201 deletions

View File

@@ -13,14 +13,9 @@ import jakarta.servlet.http.HttpServletResponse;
import org.eclipse.hawkbit.rest.exception.ResponseExceptionHandler;
import org.eclipse.hawkbit.rest.filter.ExcludePathAwareShallowETagFilter;
import org.eclipse.hawkbit.rest.util.FilterHttpResponse;
import org.eclipse.hawkbit.rest.util.HttpResponseFactoryBean;
import org.eclipse.hawkbit.rest.util.RequestResponseContextHolder;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.hateoas.config.EnableHypermediaSupport;
import org.springframework.hateoas.config.EnableHypermediaSupport.HypermediaType;
import org.springframework.http.HttpStatus;
@@ -34,31 +29,6 @@ import org.springframework.web.context.WebApplicationContext;
@EnableHypermediaSupport(type = { HypermediaType.HAL })
public class RestConfiguration {
/**
* Create filter for {@link HttpServletResponse}.
*/
@Bean
FilterHttpResponse filterHttpResponse() {
return new FilterHttpResponse();
}
/**
* Create factory bean for {@link HttpServletResponse}.
*/
@Bean
FactoryBean<HttpServletResponse> httpResponseFactoryBean() {
return new HttpResponseFactoryBean();
}
/**
* Create factory bean for {@link HttpServletResponse}.
*/
@Bean
@Scope(value = WebApplicationContext.SCOPE_REQUEST)
RequestResponseContextHolder requestResponseContextHolder() {
return new RequestResponseContextHolder();
}
/**
* {@link ControllerAdvice} for mapping {@link RuntimeException}s from the
* repository to {@link HttpStatus} codes.

View File

@@ -1,55 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.rest.util;
import java.io.IOException;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletResponse;
/**
* Filter is needed to autowire the {@link HttpServletResponse}.
*
*/
public class FilterHttpResponse implements Filter {
private ThreadLocal<HttpServletResponse> threadLocalResponse = new ThreadLocal<>();
@Override
public void init(final FilterConfig filterConfig) throws ServletException {
// not needed
}
@Override
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain)
throws IOException, ServletException {
try {
threadLocalResponse.set((HttpServletResponse) response);
chain.doFilter(request, response);
} finally {
threadLocalResponse.remove();
}
}
public HttpServletResponse getHttpServletReponse() {
return threadLocalResponse.get();
}
@Override
public void destroy() {
threadLocalResponse = null;
}
}

View File

@@ -1,56 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.rest.util;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.NamedBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
/**
*
* Factory bean to autowire the {@link HttpServletResponse}.
*
*/
public class HttpResponseFactoryBean implements FactoryBean<HttpServletResponse>, ApplicationContextAware, NamedBean {
public static final String FACTORY_BEAN_NAME = "httpResponseFactoryBean";
private ApplicationContext applicationContext;
@Override
public HttpServletResponse getObject() {
return applicationContext.getBean(FilterHttpResponse.class).getHttpServletReponse();
}
@Override
public Class<?> getObjectType() {
return HttpServletResponse.class;
}
@Override
public boolean isSingleton() {
return false;
}
@Override
public void setApplicationContext(final ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Override
public String getBeanName() {
return FACTORY_BEAN_NAME;
}
}

View File

@@ -9,36 +9,32 @@
*/
package org.eclipse.hawkbit.rest.util;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import java.util.Objects;
/**
* Store the request and response for the rest resources.
* Gives access to the request and response for the rest resources.
*/
public class RequestResponseContextHolder {
private HttpServletRequest httpServletRequest;
private HttpServletResponse httpServletResponse;
public HttpServletRequest getHttpServletRequest() {
return httpServletRequest;
public static HttpServletRequest getHttpServletRequest() {
return Objects
.requireNonNull(
(ServletRequestAttributes) RequestContextHolder.getRequestAttributes(),
"Request attribute is unavailable")
.getRequest();
}
public HttpServletResponse getHttpServletResponse() {
return httpServletResponse;
public static HttpServletResponse getHttpServletResponse() {
return Objects
.requireNonNull(
(ServletRequestAttributes) RequestContextHolder.getRequestAttributes(),
"Request attribute is unavailable")
.getResponse();
}
@Autowired
public void setHttpServletRequest(final HttpServletRequest httpServletRequest) {
this.httpServletRequest = httpServletRequest;
}
@Resource(name = HttpResponseFactoryBean.FACTORY_BEAN_NAME)
public void setHttpServletResponse(final HttpServletResponse httpServletResponse) {
this.httpServletResponse = httpServletResponse;
}
}
}

View File

@@ -13,7 +13,6 @@ import org.eclipse.hawkbit.repository.jpa.RepositoryApplicationConfiguration;
import org.eclipse.hawkbit.repository.test.TestConfiguration;
import org.eclipse.hawkbit.repository.test.util.AbstractIntegrationTest;
import org.eclipse.hawkbit.rest.filter.ExcludePathAwareShallowETagFilter;
import org.eclipse.hawkbit.rest.util.FilterHttpResponse;
import org.junit.jupiter.api.BeforeEach;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
@@ -31,17 +30,14 @@ import org.springframework.web.filter.CharacterEncodingFilter;
* Abstract Test for Rest tests.
*/
@WebAppConfiguration
@ContextConfiguration(classes = { RestConfiguration.class, RepositoryApplicationConfiguration.class,
TestConfiguration.class})
@ContextConfiguration(classes = {
RestConfiguration.class, RepositoryApplicationConfiguration.class, TestConfiguration.class})
@Import(TestChannelBinderConfiguration.class)
@AutoConfigureMockMvc
public abstract class AbstractRestIntegrationTest extends AbstractIntegrationTest {
protected MockMvc mvc;
@Autowired
private FilterHttpResponse filterHttpResponse;
@Autowired
private CharacterEncodingFilter characterEncodingFilter;
@@ -62,7 +58,6 @@ public abstract class AbstractRestIntegrationTest extends AbstractIntegrationTes
new ExcludePathAwareShallowETagFilter("/rest/v1/softwaremodules/{smId}/artifacts/{artId}/download",
"/{tenant}/controller/v1/{controllerId}/softwaremodules/{softwareModuleId}/artifacts/**",
"/api/v1/downloadserver/**"));
createMvcWebAppContext.addFilter(filterHttpResponse);
return createMvcWebAppContext;
}