CustomCitrusHttpInterceptor in citrus-framework by http-client - java

I want to attach a request-response-http to the allure-report from citrus-framework.
I wrote this class.
package com.cdek.qa_auto.common;
import io.qameta.allure.attachment.DefaultAttachmentProcessor;
import io.qameta.allure.attachment.FreemarkerAttachmentRenderer;
import io.qameta.allure.attachment.http.HttpRequestAttachment;
import io.qameta.allure.attachment.http.HttpResponseAttachment;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpRequest;
import org.springframework.http.HttpStatus;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.util.FileCopyUtils;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
public class CustomCitrusHttpInterceptor implements ClientHttpRequestInterceptor {
private String requestTemplatePath = "http-request.ftl";
private String responseTemplatePath = "http-response.ftl";
#Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body,
ClientHttpRequestExecution execution) throws IOException {
handleRequest(getRequestContent(request, new String(body)));
ClientHttpResponse response = execution.execute(request, body);
CachingClientHttpResponseWrapper bufferedResponse = new CachingClientHttpResponseWrapper(response);
handleResponse(getResponseContent(bufferedResponse));
return bufferedResponse;
}
}
and test
#SpringBootTest
#ExtendWith(CitrusExtension.class)
public class CitrusLogTest {
#Test
#com.consol.citrus.annotations.CitrusTest
void testPost1(#CitrusResource TestRunner runner) {
HttpClient todoClient = CitrusEndpoints
.http()
.client()
.interceptor(new CustomCitrusHttpInterceptor())
.requestUrl("http://address")
.build();
runner.http(action -> action
.client(todoClient)
.send()
.post("/api/tokenauth/authorize")
.contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)
.payload("{ \n" +
" \"user\":\"User\",\n" +
" \"hashedPass\":\"hashedPass\"\n" +
"}"));
runner.http(action -> action
.client(todoClient)
.receive()
.response(HttpStatus.OK)
.messageType(MessageType.JSON)
.validationCallback(new AbstractValidationCallback<String>() {
#Override
public void validate(String payload, Map<String, Object> headers, TestContext context) {
assertTrue(payload.contains("token"));
}
}));
}
}
After run test, request-response-http was not in the allure-report.
In debug, in CustomCitrusHttpInterceptor does not come.
I expect the request-response-http to be in the allure-report.

HttpClient build = CitrusEndpoints
.http()
.client()
.build();
build.getEndpointConfiguration().setClientInterceptors(Collections.singletonList(new CustomCitrusHttpInterceptor()));
The request-response-http was in the allure-report.

Related

Sprint boot custom exception not getting caught and response is always empty if error with status 200

I'm struggling a lot with spring-boot custom exception handling. Customer exception is not getting caught with exception handler. REST API works fine for valid request payload. I'm trying to send error response when there's an error. But error response is always empty with status code 200 instead of 404.
Controller
package com.company.paypage.v2.controller;
import static org.springframework.web.bind.annotation.RequestMethod.POST;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import org.json.simple.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.company.paypage.exception.*;
import com.company.paypage.model.ErrorMessageConstants;
import com.company.paypage.v2.model.ConfigPayload;
import com.company.paypage.v2.model.ConfigResponse;
import com.company.paypage.v2.services.FeatureConfigService;
import lombok.extern.slf4j.Slf4j;
#Slf4j
#RestController
#RequestMapping(value = "v2/setup")
public class FeatureConfigController {
#Autowired
private FeatureConfigService featureconfigService;
/*
features config endpoint
*/
#RequestMapping(value = "/config", method = POST, consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
public ConfigResponse setupConfigRequest(#Valid #RequestBody ConfigPayload payload, HttpServletRequest request, HttpServletResponse servResponse) {
log.info("Processing the feature config request for " + payload.getPage_type());
ConfigResponse response = null;
try {
response = featureconfigService.processConfigRequest(payload);
System.out.println(response);
if(response == null) {
throw new FeatureConfigException(ErrorMessageConstants.NOT_FOUND, "Error while generating feature config response.....");
}
} catch (FeatureConfigException e){
log.error("Exception:", e);
}
return response;
}
}
Exception class
package com.company.paypage.exception;
public class FeatureConfigException extends Exception {
String code;
String message;
public FeatureConfigException(String code, String message) {
super(message);
this.code = code;
this.message = message;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
#Override
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
Exception handler
package com.company.paypage.exception;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.servlet.NoHandlerFoundException;
import com.company.paypage.model.ApplicationConstants;
import com.company.paypage.model.ErrorCodeConstants;
import com.company.paypage.model.ErrorMessageConstants;
import com.company.paypage.model.GeneralErrorInfo;
import com.company.paypage.model.Payment;
import com.company.paypage.model.SetupResponse;
import com.company.paypage.v2.model.ConfigResponse;
import lombok.extern.slf4j.Slf4j;
#Slf4j
#ControllerAdvice
public class GeneralExceptionHandler{
#ExceptionHandler(FeatureConfigException.class)
protected ResponseEntity<ConfigResponse> handleFeatureConfigException(FeatureConfigException ex, HttpServletRequest request){
GeneralErrorInfo generalErrorInfo = new GeneralErrorInfo().withCode(ex.getCode());
generalErrorInfo.setMessage(ex.getMessage());
String referenceId =(String) request.getAttribute(ApplicationConstants.REFERENCE_ID);
ConfigResponse configResponse = buildConfigResponse(generalErrorInfo, referenceId);
log.error("{} {}-{}"
, ex.getMessage()
, request.getHeader(ApplicationConstants.X_GP_REQUEST_ID)
, referenceId
, ex);
return new ResponseEntity<ConfigResponse>(configResponse, addCustomerHeaders(request), HttpStatus.BAD_REQUEST);
}
#SuppressWarnings("null")
ConfigResponse buildConfigResponse(GeneralErrorInfo generalErrorInfo, String referenceId) {
ConfigResponse configResponse = new ConfigResponse();
configResponse.setError(generalErrorInfo);
configResponse.setAutocomplete((Boolean) null);
configResponse.setRefund((Boolean) null);
configResponse.setSplit_payment((Boolean) null);
configResponse.setTender_type(null);
configResponse.setVoidd((Boolean) null);
return configResponse;
}
}
ConfigResponse model
package com.company.paypage.v2.model;
import java.io.Serializable;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.company.paypage.model.GeneralErrorInfo;
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({
"tender_type",
"autocomplete",
"split_payment",
"refund",
"void",
"error"
})
public class ConfigResponse implements Serializable {
#JsonProperty("tender_type")
private TenderType tender_type;
#JsonProperty("autocomplete")
private boolean autocomplete;
#JsonProperty("split_payment")
private boolean split_payment;
#JsonProperty("refund")
private boolean refund;
#JsonProperty("void")
private boolean voidd;
#JsonProperty("error")
private GeneralErrorInfo error;
public TenderType getTender_type() {
return tender_type;
}
public void setTender_type(TenderType tender_type) {
this.tender_type = tender_type;
}
public boolean isAutocomplete() {
return autocomplete;
}
public void setAutocomplete(boolean autocomplete) {
this.autocomplete = autocomplete;
}
public boolean isSplit_payment() {
return split_payment;
}
public void setSplit_payment(boolean split_payment) {
this.split_payment = split_payment;
}
public boolean isRefund() {
return refund;
}
public void setRefund(boolean refund) {
this.refund = refund;
}
public boolean isVoidd() {
return voidd;
}
public void setVoidd(boolean voidd) {
this.voidd = voidd;
}
public GeneralErrorInfo getError() {
return error;
}
public void setError(GeneralErrorInfo error) {
this.error = error;
}
public ConfigResponse withError(GeneralErrorInfo error) {
setError(error);
return this;
}
}
What could be the issue here? What am I missing to get proper error in JSON format in response?
You have to define the code of an exception. Here you can find different variants of how to handle exceptions for REST: link

Why am I getting "No 'Access-Control-Allow-Origin' header is present" even though doing what the Spring documentation suggests

I'm trying to create an application like this OAuth 2.0 Authorization Server Sample, but I'm having problems with CORS.
I already did what was suggested here CORS, but I'm getting this error:
Access to XMLHttpRequest at 'http://writer:secret#localhost:8081/oauth/token' from origin 'http://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
My classes:
package br.com.sammubr.auth;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class AuthApplication {
public static void main(String[] args) {
SpringApplication.run(AuthApplication.class, args);
}
}
package br.com.sammubr.auth.configuration;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.provider.token.DefaultAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
import java.security.KeyPair;
#EnableAuthorizationServer
#Configuration
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
AuthenticationManager authenticationManager;
KeyPair keyPair;
boolean jwtEnabled;
public AuthorizationServerConfiguration(
AuthenticationConfiguration authenticationConfiguration,
KeyPair keyPair,
#Value("${security.oauth2.authorizationserver.jwt.enabled:true}") boolean jwtEnabled) throws Exception {
this.authenticationManager = authenticationConfiguration.getAuthenticationManager();
this.keyPair = keyPair;
this.jwtEnabled = jwtEnabled;
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("reader")
.authorizedGrantTypes("password")
.secret("{noop}secret")
.scopes("message:read")
.accessTokenValiditySeconds(600_000_000)
.and()
.withClient("writer")
.authorizedGrantTypes("password")
.secret("{noop}secret")
.scopes("message:write")
.accessTokenValiditySeconds(600_000_000)
.and()
.withClient("noscopes")
.authorizedGrantTypes("password")
.secret("{noop}secret")
.scopes("none")
.accessTokenValiditySeconds(600_000_000);
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints
.authenticationManager(this.authenticationManager)
.tokenStore(tokenStore());
if (this.jwtEnabled) {
endpoints
.accessTokenConverter(accessTokenConverter());
}
}
#Bean
public TokenStore tokenStore() {
if (this.jwtEnabled) {
return new JwtTokenStore(accessTokenConverter());
} else {
return new InMemoryTokenStore();
}
}
#Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setKeyPair(this.keyPair);
DefaultAccessTokenConverter accessTokenConverter = new DefaultAccessTokenConverter();
accessTokenConverter.setUserTokenConverter(new SubjectAttributeUserTokenConverter());
converter.setAccessTokenConverter(accessTokenConverter);
return converter;
}
}
package br.com.sammubr.auth.configuration;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.endpoint.FrameworkEndpoint;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
#FrameworkEndpoint
class IntrospectEndpoint {
TokenStore tokenStore;
IntrospectEndpoint(TokenStore tokenStore) {
this.tokenStore = tokenStore;
}
#PostMapping("/introspect")
#ResponseBody
public Map<String, Object> introspect(#RequestParam("token") String token) {
OAuth2AccessToken accessToken = this.tokenStore.readAccessToken(token);
Map<String, Object> attributes = new HashMap<>();
if (accessToken == null || accessToken.isExpired()) {
attributes.put("active", false);
return attributes;
}
OAuth2Authentication authentication = this.tokenStore.readAuthentication(token);
attributes.put("active", true);
attributes.put("exp", accessToken.getExpiration().getTime());
attributes.put("scope", accessToken.getScope().stream().collect(Collectors.joining(" ")));
attributes.put("sub", authentication.getName());
return attributes;
}
}
package br.com.sammubr.auth.configuration;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.RSAKey;
import org.springframework.security.oauth2.provider.endpoint.FrameworkEndpoint;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.security.KeyPair;
import java.security.interfaces.RSAPublicKey;
import java.util.Map;
#FrameworkEndpoint
class JwkSetEndpoint {
KeyPair keyPair;
JwkSetEndpoint(KeyPair keyPair) {
this.keyPair = keyPair;
}
#GetMapping("/.well-known/jwks.json")
#ResponseBody
public Map<String, Object> getKey() {
RSAPublicKey publicKey = (RSAPublicKey) this.keyPair.getPublic();
RSAKey key = new RSAKey.Builder(publicKey).build();
return new JWKSet(key).toJSONObject();
}
}
package br.com.sammubr.auth.configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
#Configuration
class KeyConfig {
#Bean
KeyPair keyPair() {
try {
String privateExponent = "3851612021791312596791631935569878540203393691253311342052463788814433805390794604753109719790052408607029530149004451377846406736413270923596916756321977922303381344613407820854322190592787335193581632323728135479679928871596911841005827348430783250026013354350760878678723915119966019947072651782000702927096735228356171563532131162414366310012554312756036441054404004920678199077822575051043273088621405687950081861819700809912238863867947415641838115425624808671834312114785499017269379478439158796130804789241476050832773822038351367878951389438751088021113551495469440016698505614123035099067172660197922333993";
String modulus = "18044398961479537755088511127417480155072543594514852056908450877656126120801808993616738273349107491806340290040410660515399239279742407357192875363433659810851147557504389760192273458065587503508596714389889971758652047927503525007076910925306186421971180013159326306810174367375596043267660331677530921991343349336096643043840224352451615452251387611820750171352353189973315443889352557807329336576421211370350554195530374360110583327093711721857129170040527236951522127488980970085401773781530555922385755722534685479501240842392531455355164896023070459024737908929308707435474197069199421373363801477026083786683";
String exponent = "65537";
RSAPublicKeySpec publicSpec = new RSAPublicKeySpec(new BigInteger(modulus), new BigInteger(exponent));
RSAPrivateKeySpec privateSpec = new RSAPrivateKeySpec(new BigInteger(modulus), new BigInteger(privateExponent));
KeyFactory factory = KeyFactory.getInstance("RSA");
return new KeyPair(factory.generatePublic(publicSpec), factory.generatePrivate(privateSpec));
} catch (Exception e) {
throw new IllegalArgumentException(e);
}
}
}
package br.com.sammubr.auth.configuration;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.oauth2.provider.token.DefaultUserAuthenticationConverter;
import java.util.LinkedHashMap;
import java.util.Map;
class SubjectAttributeUserTokenConverter extends DefaultUserAuthenticationConverter {
#Override
public Map<String, ?> convertUserAuthentication(Authentication authentication) {
Map<String, Object> response = new LinkedHashMap<>();
response.put("sub", authentication.getName());
if (authentication.getAuthorities() != null && !authentication.getAuthorities().isEmpty()) {
response.put(AUTHORITIES, AuthorityUtils.authorityListToSet(authentication.getAuthorities()));
}
return response;
}
}
package br.com.sammubr.auth.configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import java.util.Arrays;
import java.util.Collections;
import static org.springframework.security.config.Customizer.withDefaults;
#Configuration
class UserConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors(withDefaults())
.authorizeRequests()
.mvcMatchers("/.well-known/jwks.json").permitAll()
.anyRequest().authenticated()
.and()
.httpBasic()
.and()
.csrf().ignoringRequestMatchers(request -> "/introspect".equals(request.getRequestURI()));
}
#Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Collections.singletonList("*"));
configuration.setAllowedMethods(Arrays.asList("GET", "POST"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
#Bean
#Override
public UserDetailsService userDetailsService() {
return new InMemoryUserDetailsManager(
User.withDefaultPasswordEncoder()
.username("subject")
.password("password")
.roles("USER")
.build());
}
}
And my request is simple like this:
import $ from 'jquery';
window.jQuery = $;
window.$ = $;
import axios from "axios";
let api = axios.create({
baseURL: 'http://writer:secret#localhost:8081',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
});
$(document).ready(function() {
$("input[type=submit]").on("click", function(ev) {
ev.preventDefault();
const params = new URLSearchParams();
params.append('username', 'subject');
params.append('password', 'password');
params.append('grant_type', 'password');
api.post('/oauth/token', params)
.then((resp) => {
console.log(resp.data)
}).catch(error => console.error(error));
});
});
I'm doing what you say in the Spring documentation, but it's not working. Can someone help me?

ExceptionHandlerExceptionResolver always returns 200 response code in Spring 5

I have upgraded from Spring 4.2 to Spring 5.0.5. After upgrading my junits are failing with the below error.
java.lang.AssertionError: Testing return value. expected:<405> but was:<200>
at org.junit.Assert.fail(Assert.java:88)
at org.junit.Assert.failNotEquals(Assert.java:834)
at org.junit.Assert.assertEquals(Assert.java:645)
at
Below is my code:
`package com.hp.ci.mgmt.controllers;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.ResourceBundle;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.springframework.beans.TypeMismatchException;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import
org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.multipart.MultipartException;
import
org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;
import com.fasterxml.jackson.core.JsonLocation;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException;
public class AbstractBaseControllerTest extends AbstractBaseController
{
ExceptionHandlerExceptionResolver resolver = new ExceptionHandlerExceptionResolver();
ObjectMapper mapper = new ObjectMapper();
private MockHttpServletRequest request;
private MockHttpServletResponse response;
#Mock
CiException cie;
#SuppressWarnings("rawtypes")
#Before
public void setup()
{
final List<HttpMessageConverter<?>> messageConvertersList = new ArrayList<HttpMessageConverter<?>>();
messageConvertersList.add(new MappingJackson2HttpMessageConverter());
resolver.setMessageConverters(messageConvertersList);
request = new MockHttpServletRequest();
response = new MockHttpServletResponse();
MockitoAnnotations.initMocks(this);
Mockito.when(cie.getErrorSource()).thenReturn("test");
}
#Test
public void testUnsupportedOperationException()
throws Exception
{
validateException(HttpStatus.METHOD_NOT_ALLOWED, new RequestNotAllowedException());
}
private void validateException(final HttpStatus expectedStatus, final
Exception e)
throws Exception
{
validateExceptionStatus(expectedStatus, e);
}
private void validateExceptionStatus(final HttpStatus expectedStatus, final Exception e)
throws Exception
{
resolver.resolveException(request, response, this, e);
if (expectedStatus == null)
{
assertEquals("Testing return value.", HttpStatus.BAD_REQUEST.value(), response.getStatus());
}
else
{
assertEquals("Testing return value.", expectedStatus.value(), response.getStatus());
}
}
Issue is that the below code always returns 200 status code, therefore all my tests fail.
resolver.resolveException(request, response, this, e);
Does anyone know how to resolve this issue?
I found what is causing the issue. Looks like "this" in the below line does not extend HandlerMethod so resolveException returns null without doing anything.
resolver.resolveException(request, response, this, e);
#Override
protected boolean shouldApplyTo(HttpServletRequest request, #Nullable Object
handler) {
if (handler == null) {
return super.shouldApplyTo(request, null);
}
else if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
handler = handlerMethod.getBean();
return super.shouldApplyTo(request, handler);
}
else {
return false;
}
}
Can someone help me with configuring the handler. How can i implement HandlerMethod?

Accessing Request Headers

How to access request headers in implementation of WriterInterceptor interface in JAX-RS?
context.getHeaders(); //This line gives a set of response headers(not request headers) in the WriterInterceptor implementation.
Complete code below:
public class GzipFilterWriterInterceptor implements WriterInterceptor {
private static final Logger LOG = LoggerFactory.getLogger(GzipFilterWriterInterceptor.class);
#Override
public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException {
MultivaluedMap<String,Object> headers = context.getHeaders();
headers.add("Content-Encoding", "gzip");
final OutputStream outputStream = context.getOutputStream();
context.setOutputStream(new GZIPOutputStream(outputStream));
context.proceed();
}
}
You can just inject HttpHeaders. It will be a thread-local proxy when it's injected, so it's thread safe.
#Context
private HttpHeaders headers;
It has methods
String getHeaderString(String name)
List<String> getRequestHeader(String name)
MultivaluedMap<String,String> getRequestHeaders()
UPDATE (test)
import org.glassfish.jersey.filter.LoggingFilter;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.Provider;
import javax.ws.rs.ext.WriterInterceptor;
import javax.ws.rs.ext.WriterInterceptorContext;
import java.io.IOException;
import java.util.logging.Logger;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
/**
* Run like any other JUnit test. Only one required dependency:
*
* <dependency>
* <groupId>org.glassfish.jersey.test-framework.providers</groupId>
* <artifactId>jersey-test-framework-provider-inmemory</artifactId>
* <scope>test</scope>
* <version>${jersey.version}</version>
* </dependency>
*/
public class HeadersTest extends JerseyTest {
#Path("hello")
public static class HelloResource {
#GET
public String get() {
return "Hello";
}
}
#Override
public ResourceConfig configure() {
return new ResourceConfig(HelloResource.class)
.register(HeaderWriter.class)
.register(new LoggingFilter(Logger.getAnonymousLogger(), true));
}
#Provider
public static class HeaderWriter implements WriterInterceptor {
#Context
private HttpHeaders headers;
#Override
public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException {
context.proceed();
final String header = headers.getHeaderString("X-Request-Header");
context.getHeaders().add("X-Response-Header", header);
}
}
#Test
public void doit() {
final Response response = target("hello").request()
.header("X-Request-Header", "BooYah")
.get();
assertThat(response.getHeaderString("X-Response-Header"), is("BooYah"));
}
}
You can implement below code to ,see working example at http://jerseyexample-ravikant.rhcloud.com/rest/jws/say/Hello
import java.io.IOException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.ext.Provider;
#Provider
public class SecurityInterceptor implements ContainerRequestFilter, ContainerResponseFilter {
#Override
public void filter(ContainerRequestContext reqCtx, ContainerResponseContext respCtx) throws IOException {
long startTime=0;
System.out.println("Adding ProcessingTime in response headers");
if(reqCtx.getHeaderString("startTime")!=null)
startTime = Long.parseLong(reqCtx.getHeaderString("startTime"));
respCtx.getHeaders().add("ProcessingTime",
String.valueOf(System.currentTimeMillis() - startTime) + " millisecs");
}
#Override
public void filter(ContainerRequestContext reqCtx) throws IOException {
System.out.println("Adding start time in request headers");
reqCtx.getHeaders().add("startTime", String.valueOf(System.currentTimeMillis()));
}
}
#Provider
public class GzipFilterWriterInterceptor implements WriterInterceptor
{
private static final Logger LOG = LoggerFactory.getLogger(GzipFilterWriterInterceptor.class);
// use a context injection
#Context
private HttpHeaders httpHeaders;
#Override
public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException
{
MultivaluedMap<String,Object> headers = context.getHeaders();
headers.add("Content-Encoding", "gzip");
// do stuff with headers
if ("Basic Ym9iOnBhc3N3b3Jk".equals(httpHeaders.getRequestHeader("Authorization").get(0)))
{
//do stuff here, but be careful about the indexoutofbounds...
}
final OutputStream outputStream = context.getOutputStream();
context.setOutputStream(new GZIPOutputStream(outputStream));
context.proceed();
}
}
The context injection will be injected per request, see the javadocs.
Probably not best solution, but you can have your interceptor implementing ReaderInterceptor. There you can get headers and save them in ThreadLocal variable so you can access then in WriterInterceptor
Also if you have annotation based configuration you can try to inject ContainerRequestContext with a #Context annotation

Could not write request: no suitable HttpMessageConverter found for request type and content type [application/x-java-serialized-object]

I am trying to post an xml request to a third party server and expecting an xml response back.
I am here by attaching the source code for configuring Cnfiguration,gateways & channels, Customized Rest Template class and Test Client to execute. We have various message converters for XML Posting but despite that it is always saying no suitable HTTPMessage Converters
/**** Gateway & Channel Configuration class****/
#Configuration
#MessagingGateway(name = "EntryGateway", defaultRequestChannel = "EntryChannel", defaultRequestTimeout = "2000", defaultReplyChannel = "ExitChannel", defaultReplyTimeout = "2000")
public interface Gateway {
#Gateway(requestChannel = "EntryChannel", requestTimeout = Constants.REQUEST_TIMEOUT_IN_MILLISECONDS, replyChannel = "ExitChannel", replyTimeout = Constants.RESPONSE_TIMEOUT_IN_MILLISECONDS)
ReqResMessage sendRequest(ReqResMessage request);
}
import java.util.ArrayList;
import java.util.List;
import org.aopalliance.aop.Advice;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.converter.FormHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.xml.MarshallingHttpMessageConverter;
import org.springframework.integration.annotation.IntegrationComponentScan;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.config.EnableIntegration;
import org.springframework.integration.http.outbound.HttpRequestExecutingMessageHandler;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHandler;
import org.springframework.messaging.converter.MessageConverter;
import org.springframework.oxm.Marshaller;
import org.springframework.oxm.Unmarshaller;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
#Configuration
#ComponentScan("package_name")
#IntegrationComponentScan("package_name")
#EnableIntegration
#Import(value = ExternalSystemsConfiguration.class)
#PropertySource(value = "classpath:properties", ignoreResourceNotFound = true)
public class Configuration {
private static final Logger logger = LogbackConfig.getApplicationLogger(POPConfiguration.class);
#Autowired
Environment env;
#Autowired
ExternalSystemsConfiguration externalSystemsConfiguration;
/**
* Entry channel to the messaging system through the gateway.
*
* #return MessageChannel
*/
#Bean
public MessageChannel EntryChannel() {
return new DirectChannel();
}
#Bean
public MessageChannel RequestChannel() {
return new DirectChannel();
}
#Bean
public MessageChannel ResponseChannel() {
return new DirectChannel();
}
#Bean
public MessageChannel ExitChannel() {
return new DirectChannel();
}
#Bean
#ServiceActivator(inputChannel = "RequestChannel")
public MessageHandler cmmHttpGateway() throws Exception {
logger.debug("Entered Configuration httpGateway() ");
List<Advice> retryAdvices = new ArrayList<>();
retryAdvices.add(externalSystemsConfiguration.requestHandlerRetryAdvice());
HttpRequestExecutingMessageHandler handler = new HttpRequestExecutingMessageHandler(env.getProperty("url")
);
List<HttpMessageConverter<?>> converters = new ArrayList<>();
converters.add(marshallingMessageConverter());
handler.setMessageConverters(converters);
handler.setOutputChannel(popResponseChannel());
handler.setRequiresReply(true);
//handler.setExtractPayload(true);
// handler.
handler.setHttpMethod(HttpMethod.POST);
logger.debug("Exited Configuration httpGateway() ");
return handler;
}
#Bean
public MarshallingHttpMessageConverter marshallingMessageConverter() {
return new MarshallingHttpMessageConverter(
jaxb2Marshaller(),
jaxb2Marshaller()
);
}
#Bean
public Jaxb2Marshaller jaxb2Marshaller() {
System.out.println("jaxb2Marshaller");
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setClassesToBeBound(new Class[]{
ReqResMessage.class,
ReqResBody.class,
ReqResHeader.class,
Request.class,
Response.class
});
return marshaller;
}
}
/***** Rest Template Comfiguration ******/
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import org.apache.http.Header;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthOption;
import org.apache.http.auth.AuthScheme;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.MalformedChallengeException;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.AuthCache;
import org.apache.http.client.AuthenticationStrategy;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpHead;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.params.HttpClientParams;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.conn.params.ConnRoutePNames;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.BasicAuthCache;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.DefaultRedirectStrategy;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.LaxRedirectStrategy;
import org.apache.http.impl.client.ProxyAuthenticationStrategy;
import org.apache.http.message.BasicHeader;
import org.apache.http.protocol.HttpContext;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.http.converter.FormHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter;
import org.springframework.http.converter.xml.MarshallingHttpMessageConverter;
import org.springframework.integration.handler.advice.RequestHandlerRetryAdvice;
import org.springframework.oxm.Marshaller;
import org.springframework.oxm.Unmarshaller;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import org.springframework.retry.backoff.FixedBackOffPolicy;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.retry.support.RetryTemplate;
import org.springframework.web.client.RestTemplate;
#Configuration
#PropertySource(value ="classpath:integration.properties", ignoreResourceNotFound =true)
public class ExternalSystemsConfiguration {
#Autowired
Environment env;
private static final Logger logger = LogbackConfig.getApplicationLogger(ExternalSystemsConfiguration.class);
#Bean
public RequestHandlerRetryAdvice requestHandlerRetryAdvice() {
logger.debug("Entered RetryConfiguration requestHandlerRetryAdvice()");
RequestHandlerRetryAdvice retryAdvice = new RequestHandlerRetryAdvice();
RetryTemplate retryTemplate = new RetryTemplate();
FixedBackOffPolicy fixedBackOffPolicy = new FixedBackOffPolicy();
SimpleRetryPolicy simpleRetryPolicy = new SimpleRetryPolicy();
simpleRetryPolicy.setMaxAttempts(Integer.parseInt(env.getProperty("retryAttempts")));
fixedBackOffPolicy.setBackOffPeriod(Integer.parseInt(env.getProperty("backOffPolicy")));
retryTemplate.setBackOffPolicy(fixedBackOffPolicy);
retryTemplate.setRetryPolicy(simpleRetryPolicy);
retryAdvice.setRetryTemplate(retryTemplate);
return retryAdvice;
}
/**
* This method is used to create rest template with configurable read and connection timeouts.It is used by all http gateways.
* #return RestTemplate
*/
#SuppressWarnings("deprecation")
#Bean
public RestTemplate getRestTemplate(){
RestTemplate restTemplate = new RestTemplate();
BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(new AuthScope("test.com", 443), new UsernamePasswordCredentials("testuser", "testpassword"));
HttpHost target = new HttpHost("test", 443, "https");
System.out.println("BASE64:"+credentialsProvider.toString());
// Create AuthCache instance
AuthCache authCache = new BasicAuthCache();
// Generate BASIC scheme object and add it to the local auth cache
BasicScheme basicAuth = new BasicScheme();
authCache.put(target, basicAuth);
// Add AuthCache to the execution context
HttpClientContext context = HttpClientContext.create();
context.setCredentialsProvider(credentialsProvider);
context.setAuthCache(authCache);
Header header = new BasicHeader(HttpHeaders.CONTENT_TYPE, "application/xml");
List<Header> headers = new ArrayList<>();
headers.add(header);
HttpHost proxy = new HttpHost("", "", "http");
RequestConfig config = RequestConfig.custom()
.setProxy(proxy)
.build();
CloseableHttpClient httpClient = HttpClientBuilder.create().setProxy(proxy).setDefaultHeaders(headers).setProxyAuthenticationStrategy(new ProxyAuthenticationStrategy())
.setDefaultCredentialsProvider(credentialsProvider).setRedirectStrategy(new DefaultRedirectStrategy() {
private String[] REDIRECT_METHODS = new String[] {
HttpGet.METHOD_NAME, HttpHead.METHOD_NAME
};
#Override
protected boolean isRedirectable(String method) {
for (String m : REDIRECT_METHODS) {
if (m.equalsIgnoreCase(method)) {
return true;
}
}
return false;
}
})
.build();
restTemplate.setRequestFactory(new Conn());
/* List<HttpMessageConverter<?>> converters = new ArrayList<>();
converters.add(marshallingMessageConverter());
converters.add(new FormHttpMessageConverter());
converters.add(new StringHttpMessageConverter());
restTemplate.setMessageConverters(converters);*/
return restTemplate;
}
public class Conn extends SimpleClientHttpRequestFactory {
public Conn(){
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("", 8080));
this.setProxy(proxy);
}
#Override
protected void prepareConnection(HttpURLConnection connection, String httpMethod) throws IOException {
// TODO Auto-generated method stub
super.prepareConnection(connection, httpMethod);
connection.setFollowRedirects(true);
String userpassword = "testuser" + ":" + "testpassword";
String encodedAuthorization = Base64.getEncoder().encodeToString(userpassword.getBytes());
System.out.println("basic-----" + encodedAuthorization);
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.addRequestProperty("Authorization", "Basic " + encodedAuthorization);
connection.addRequestProperty("content-type", "application/xml");
}
}
}
/***** Test Client to Post XML Request in the form of Java object as well as String *****/
*/
#ContextConfiguration(classes = Configuration.class)
#RunWith(SpringJUnit4ClassRunner.class)
public class Test {
private static Logger logger = LogbackConfig.getApplicationLogger(Test.class);
#Autowired
private Gateway cmmGateway;
#Autowired
RestTemplate template;
#Test
public void testJsonResponse() {
String xml = "<?xml version=\"1.0\"?>"
+"<Message>"
+ "<Header><NCPDPID>3942100</NCPDPID><SentTime>2016-07-14 06:13:00</SentTime>"
+ "<SenderID>01hw320985</SenderID><MaxRowCount>500</MaxRowCount>"
+ "</Header><Body><Request><Distance>100.00</Distance><LastName>ALLEN</LastName>"
+ "<FirstName></FirstName><Gender></Gender><Phone></Phone><City></City>"
+ "<State></State><LicensedState></LicensedState>" + "<DEA></DEA>"
+ "" + "</Request>"
+ "</Body>" + "</Message>";/*
ReqResMessage user=null;
try{
JAXBContext jaxbContext = JAXBContext.newInstance(ReqResMessage.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
InputStream is = new ByteArrayInputStream(xml.getBytes());
user= (ReqResMessage) jaxbUnmarshaller.unmarshal(is);
// System.out.println("REquest****"+user.getBody().getRequest());
}catch(Exception e){
e.printStackTrace();
}*/
ReqResMessage re = new ReqResMessage();
ReqResHeader header= new ReqResHeader();
header.setPharmacyNCPDPID("3942100");
header.setRowCount("500");
header.setSenderID("01hw320985");
Request request = new Request();
request.setDistance("100.00");
request.setLastName("ALLEN");
ReqResBody body = new ReqResBody();
body.setRequest(request);
re.setBody(body);
re.setHeader(header);
//System.out.println("Before:"+System.currentTimeMillis());
ReqResMessage response = cmmGateway.sendRequest(re);
}
}
Finally i found solution by setting header enricher out put channel to be passed as request channel to httpoutbound gateway. Find below code snippet,there i set content-type to application/xml that resolves problem.
#Bean
#Transformer(inputChannel = "RequestChannel", outputChannel = "enricherOutputChannel")
public HeaderEnricher makeEnricher() {
Map<String, ? extends HeaderValueMessageProcessor<?>> headersToAdd = Collections
.singletonMap(HttpHeaders.CONTENT_TYPE, new StaticHeaderValueMessageProcessor<>("application/xml"));
HeaderEnricher enricher = new HeaderEnricher(headersToAdd);
enricher.setDefaultOverwrite(true);
return enricher;
}

Categories

Resources