Read custom header value from the response - spring-boot

When I send request from the Soap UI under raw response tab I see the following result(find attachment). Now in AOP controller I want to read this header value which is marked as red. How it is possible? Thanks in advance.

In my application to send soap requests I have WebServiceTemplate. I applied custom interceptor WebServiceInterceptor (which implements ClientInterceptor interface) on this web service template. In overridden afterCompletion method, which injects MessageContext, I was able to take this property from the SaajMessageHeader.
Here is what code looks like:
#Configuration
public class MyWebServiceConfig {
#Bean(name = "myWSClient")
public WebServiceTemplate myWSClient() throws Exception {
WebServiceTemplate template = new WebServiceTemplate();
...
WebServiceInterceptor[] interceptors = { new WebServiceInterceptor() };
template.setInterceptors(interceptors);
return template;
}
private static class WebServiceInterceptor implements ClientInterceptor {
#Override
public boolean handleRequest(MessageContext messageContext) throws WebServiceClientException {
...
return true;
}
#Override
public boolean handleResponse(MessageContext messageContext) throws WebServiceClientException {
return true;
}
#Override
public boolean handleFault(MessageContext messageContext) throws WebServiceClientException {
return true;
}
#Override
public void afterCompletion(MessageContext messageContext, Exception ex) throws WebServiceClientException {
try {
SaajSoapMessage message = (SaajSoapMessage) messageContext.getResponse();
String []traceId = message.getSaajMessage().getMimeHeaders().getHeader("ITRACING_TRACE_ID");
if(traceId != null && traceId.length > 0){
process.setTraceId(traceId[0]);
}
} catch (Exception e) {
}
}
}

Related

Is there a way to integrate Springs #ExceptionHandler with Joinfaces

i wanted to ask if there is a way to enable Springs #ExceptionHandler capabilities with Joinfaces/Primefaces.
For now i'm able to handle global #ControllerAdvice beans, but not if the #ExceptionHandler is inside the #Controller class.
Are there any suggestions on how to solve this topic?
Here is the code i wrote so far
#Slf4j
public class SpringJsfExceptionHandler extends ExceptionHandlerWrapper {
public SpringJsfExceptionHandler(ExceptionHandler wrapped) {
super(wrapped);
}
#Override
public void handle() throws FacesException {
final Iterator<ExceptionQueuedEvent> queue = getUnhandledExceptionQueuedEvents().iterator();
while (queue.hasNext()) {
ExceptionQueuedEvent item = queue.next();
ExceptionQueuedEventContext exceptionQueuedEventContext = (ExceptionQueuedEventContext) item.getSource();
try {
Throwable throwable = exceptionQueuedEventContext.getException();
FacesContext context = FacesContext.getCurrentInstance();
handleException(context, (Exception) throwable);
} finally {
queue.remove();
}
}
}
private void handleException(FacesContext context, Exception throwable) {
WebApplicationContext applicationContext = resolveApplicationContext(context);
Collection<HandlerExceptionResolver> exceptionResolvers = listExceptionHandlerResolvers(applicationContext);
for (HandlerExceptionResolver resolver : exceptionResolvers) {
resolver.resolveException(request(context), response(context), null, throwable);
}
}
private Collection<HandlerExceptionResolver> listExceptionHandlerResolvers(WebApplicationContext context) {
return context.getBeansOfType(HandlerExceptionResolver.class).values();
}
private HttpServletRequest request(FacesContext context) {
return (HttpServletRequest) context.getExternalContext().getRequest();
}
private HttpServletResponse response(FacesContext context) {
return (HttpServletResponse) context.getExternalContext().getResponse();
}
private WebApplicationContext resolveApplicationContext(FacesContext context) {
HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest();
return WebApplicationContextUtils.findWebApplicationContext(request.getServletContext());
}
}
public class SpringJsfExceptionHandlerFactory extends ExceptionHandlerFactory {
public SpringJsfExceptionHandlerFactory() {
}
public SpringJsfExceptionHandlerFactory(ExceptionHandlerFactory wrapped) {
super(wrapped);
}
#Override
public ExceptionHandler getExceptionHandler() {
return new SpringJsfExceptionHandler(getWrapped() != null ? getWrapped().getExceptionHandler() : null);
}
}
This works:
#ControllerAdvice
public class GlobalExceptionHandler {
#ExceptionHandler
public void handleCalculationException(CalculationException e) {
FacesContext.getCurrentInstance().
addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, e.getMessage(), e.getMessage()));
}
}
This does not work:
#Data
#Controller
#ViewScoped
public class CalculatorController implements Serializable {
#ExceptionHandler
public void handleCalculationException(CalculationException e) {
FacesContext.getCurrentInstance().
addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, e.getMessage(), e.getMessage()));
}
[...]
Thanks in advance
TLDR: No
#ExceptionHandler is part of Spring MVC.
Spring MVC and JSF are separate web frameworks.
Joinfaces allows you to use JSF in a Spring Application, and you can also use Spring MVC in the same application. Every request will however either be handled by Spring MVC (i.e. the DispatcherServlet) or JSF (i.e. the FacesServlet).

Handling SOAP Fault in Spring Boot WebServiceTemplate

I am new to SOAP, trying to run a sample SOAP client using Spring Boot
How the SOAP fault, Exceptions or Errors are handled while using WebServiceTemplate
public class CountryClient extends WebServiceGatewaySupport {
private static final Logger log = LoggerFactory.getLogger(CountryClient.class);
public GetCountryResponse getCountry(String country) {
GetCountryRequest request = new GetCountryRequest();
request.setName(country);
log.info("Requesting location for " + country);
GetCountryResponse response = (GetCountryResponse) getWebServiceTemplate()
.marshalSendAndReceive("http://localhost:8080/ws/countries", request,
new SoapActionCallback(
"http://spring.io/guides/gs-producing-web-service/GetCountryRequest"));
return response;
}
}
One way is writing your custom interceptor which implements Spring WS's ClientInterceptor interface. You should override handleFault method to handle SOAP faults with your custom logic.
public class MySoapClientInterceptor implements ClientInterceptor {
private static final Logger LOGGER = LoggerFactory.getLogger(MySoapClientInterceptor.class);
#Override
public boolean handleRequest(MessageContext messageContext) throws WebServiceClientException {
return true;
}
#Override
public boolean handleResponse(MessageContext messageContext) throws WebServiceClientException {
return true;
}
#Override
public boolean handleFault(MessageContext messageContext) throws WebServiceClientException {
LOGGER.info("intercepted a fault...");
SoapBody soapBody = getSoapBody(messageContext);
SoapFault soapFault = soapBody.getFault();
LOGGER.error(soapFault.getFaultStringOrReason());
throw new RuntimeException(String.format("Error occured while invoking SOAP service - %s ", soapFault.getFaultStringOrReason()));
}
#Override
public void afterCompletion(MessageContext messageContext, Exception ex) throws WebServiceClientException {
}
private SoapBody getSoapBody(MessageContext messageContext) {
SoapMessage soapMessage = (SoapMessage) messageContext.getResponse();
SoapEnvelope soapEnvelope = soapMessage.getEnvelope();
return soapEnvelope.getBody();
}
}
Then you need to register your custom Interceptor class as an interceptor at your SOAP client config class. At the bean definition of CountryClient at your Configuration class in your case.
#Configuration
public class SoapClientConfig {
#Value("${soap.server.url}")
public String soap_server_url;
#Bean
public Jaxb2Marshaller marshaller() {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setContextPath("com.example");
return marshaller;
}
#Bean
public SoapConnector soapConnector(Jaxb2Marshaller marshaller) {
SoapConnector client = new SoapConnector();
client.setDefaultUri(soap_server_url);
client.setMarshaller(marshaller);
client.setUnmarshaller(marshaller);
ClientInterceptor[] clientInterceptors = {new MySoapClientInterceptor()};
client.setInterceptors(clientInterceptors);
return client;
}
}

How i can pass new Object between Zuul filters, using spring context?

Currently, I have AuthFilter and here I received an UserState. I need to pass it to the next Filter. But how to do it right? Or exists other practices to resolve it?
public class AuthFilter extends ZuulFilter {
#Autowired
private AuthService authService;
#Autowired
private ApplicationContext appContext;
#Override
public String filterType() {
return PRE_TYPE;
}
#Override
public int filterOrder() {
return PRE_DECORATION_FILTER_ORDER - 2;
}
#Override
public boolean shouldFilter() {
RequestContext context = RequestContext.getCurrentContext();
String requestURI = context.getRequest().getRequestURI();
for (String authPath : authPaths) {
if (requestURI.contains(authPath)) return true;
}
return false;
}
#Override
public Object run() throws ZuulException {
try {
UserState userState = authService.getUserData();
DefaultListableBeanFactory context = new DefaultListableBeanFactory();
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(UserState.class);
beanDefinition.setPropertyValues(new MutablePropertyValues() {
{
add("user", userState);
}
});
context.registerBeanDefinition("userState", beanDefinition);
} catch (UndeclaredThrowableException e) {
if (e.getUndeclaredThrowable().getClass() == UnauthorizedException.class) {
throw new UnauthorizedException(e.getMessage());
}
if (e.getUndeclaredThrowable().getClass() == ForbiddenException.class) {
throw new ForbiddenException(e.getMessage(), "The user is not allowed to make this request");
}
}
return null;
}
}
I pretty sure filters are chained together and the request/response are passed through them. You can add the data to the request, and have the next filter look for it.

Spring Batch MultiResourceItemReader re-reading first resource

I am writing a Spring Batch application using Spring Boot 1.5, following are my classes : -
CustomMultiResourceItemReader.java
#StepScoped
#Component
public class CustomMultiResourceItemReader
extends MultiResourceItemReader<MyDTO> {
public MultiResourceXmlItemReader(
#NonNull final MyResourceAwareItemReader itemReader,
#NonNull final ApplicationContext ctx)
throws IOException {
setResources(
ctx.getResources(
String.format(
"file:%s/*.xml", "~/data"))); // gives me a Resource[] array fine
setDelegate(itemReader);
}
#PreDestroy
void destroy() {
close();
}
}
MyResourceAwareItemReader.java
#RequiredArgsConstructor
#StepScope
#Component
#Slf4j
public class MyResourceAwareItemReader
implements ResourceAwareItemReaderItemStream<MyDTO> {
private static final String RESOURCE_NAME_KEY = "RESOURCE_NAME_KEY";
#NonNull private final Unmarshaller unmarshaller; // JaxB Unmarshaller
private Resource resource;
#Override
public void setResource(Resource resource) {
this.resource = resource; // **gets called only once**
}
#Override
public MyDTO read() throws Exception {
final MyDTO dto = (MyDTO) unmarshaller.unmarshal(resource.getFile()); // Standard JaxB unmarshalling.
return dto;
}
#Override
public void open(ExecutionContext executionContext) throws ItemStreamException {
if (executionContext.containsKey(RESOURCE_NAME_KEY)) {
} else if (resource != null) {
executionContext.put(RESOURCE_NAME_KEY, resource.getFilename());
}
}
#Override
public void update(ExecutionContext executionContext) throws ItemStreamException {
if (resource != null) executionContext.put(RESOURCE_NAME_KEY, resource.getFilename());
}
#Override
public void close() throws ItemStreamException {}
}
The problem is the setResource method in the delegate reader (MyResourceAwareItemReader.java) gets called only once at the beginning; while the read method gets called multiple times, as a result I read the same item multiple times, instead of reading the next item as expected.
I have also browsed the source code of MultiResouceItemReader in Spring Batch, it seems like, the read method of the delegate class is supposed to return null after each item is read, I can clearly see my code doesnt seem to do that.
I am bit lost how to make this work. Any help is much appreciated
Looking further into it, ItemReader documentation, clearly details that reader must return null at the end of the input data set. So basically I implemented my ItemReader with a boolean flag as follows: -
#RequiredArgsConstructor
#StepScope
#Component
#Slf4j
public class MyResourceAwareItemReader
implements ResourceAwareItemReaderItemStream<MyDTO> {
private static final String RESOURCE_NAME_KEY = "RESOURCE_NAME_KEY";
#NonNull private final Unmarshaller unmarshaller; // JaxB Unmarshaller
private Resource resource;
private boolean isResourceRead;
#Override
public void setResource(Resource resource) {
this.resource = resource;
isResourceRead = false;
}
#Override
public MyDTO read() throws Exception {
if(isResourceRead == true) return null;
final MyDTO dto = (MyDTO) unmarshaller.unmarshal(resource.getFile());
isResourceRead = true;
return dto;
}
#Override
public void open(ExecutionContext executionContext) throws ItemStreamException {
if (executionContext.containsKey(RESOURCE_NAME_KEY)) {
} else if (resource != null) {
executionContext.put(RESOURCE_NAME_KEY, resource.getFilename());
}
}
#Override
public void update(ExecutionContext executionContext) throws ItemStreamException {
if (resource != null) executionContext.put(RESOURCE_NAME_KEY, resource.getFilename());
}
#Override
public void close() throws ItemStreamException {}
}
MultiResourceItemReader does not returns null each time. If there are no more resources to read the it returns NULL otherwise it returns the next resources to the delegate that means – Your actual reader
I can see problem in your read() method . you are not moving to next file. As you are implementing you own MultiResourceItemReader It’s your responsibility to move to next resources item.
This is how it is implanted in MultiResourceItemReader . You will need your own similar implementation.
private T readNextItem() throws Exception {
T item = delegate.read();
while (item == null) {
currentResource++;
if (currentResource >= resources.length) {
return null;
}
delegate.close();
delegate.setResource(resources[currentResource]);
delegate.open(new ExecutionContext());
item = delegate.read();
}
return item;
}
You need to maintain index of resources array . Please check implementation of MultiResourceItemReader. You need to do exactly similar way

Spring MVC with Atmosphere

I have recently started with Atmosphere. I need it to implement it in a Spring MVC application.
Till now I've managed to integrate it with Spring MVC.
I just need to perform a very simple task. I have a counter an instance variable as soon as it reaches 10, a response should be broadcasted to the UI.
Can anyone help me how do I write the code for that in the controller.
I've got the Atmosphere resource into the controller.
AtmosphereArgumentResolver.java
public class AtmosphereArgumentResolver implements HandlerMethodArgumentResolver {
//#Override
public boolean supportsParameter(MethodParameter parameter) {
return AtmosphereResource.class.isAssignableFrom(parameter.getParameterType());
}
//#Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception
{
HttpServletRequest httpServletRequest= webRequest.getNativeRequest(HttpServletRequest.class);
return Meteor.build(httpServletRequest).getAtmosphereResource();
}
}
HomeController.java
#Controller
public class HomeController {
private int counter = 0;
private final BroadcasterFactory bf;
public BroadcasterFactory broadcasterFactory()
{
return BroadcasterFactory.getDefault();
}
for(int i=0; i<=15; i++)
{
counter ++;
}
// As soon as the counter reaches 10 I need to send a broadcast message to the UI.
}
Can anyone please help? A skeleton code would also help as in which Atmosphere method to use for this?
I will copy/past the code i use in my application :
Controller :
#ManagedService(path = "/websocket/*")
#Singleton
public class LanesWebSocket {
private final Logger logger = LoggerFactory.getLogger(LanesWebSocket.class);
// private ScheduledExecutorService scheduledExecutorService;
private Future<?> scheduleFixedBroadcast;
private final ObjectMapper mapper = new ObjectMapper();
private SupervisionCenterService supervisionCenterService;
#Ready
public void onReady(final AtmosphereResource resource) {
if (this.supervisionCenterService == null)
supervisionCenterService = SpringApplicationContext.getBean(SupervisionCenterService.class);
Broadcaster bc = BroadcasterFactory.getDefault().lookup("lanes",true);
bc.addAtmosphereResource(resource);
scheduleFixedBroadcast = bc.scheduleFixedBroadcast(new Callable<String>() {
#Override
public String call() throws Exception {
try {
return mapper.writeValueAsString(supervisionCenterService.findCenterData());
} catch (Exception e) {
scheduleFixedBroadcast.cancel(true);
e.printStackTrace();
return null;
}
}
}, 1, TimeUnit.SECONDS);
}
And you also need to register the atmosphere servlet :
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
[...]
#Override
protected void registerDispatcherServlet(ServletContext servletContext) {
super.registerDispatcherServlet(servletContext);
initAtmosphereServlet(servletContext);
}
private void initAtmosphereServlet(ServletContext servletContext) {
AtmosphereServlet servlet = new AtmosphereServlet();
Field frameworkField = ReflectionUtils.findField(AtmosphereServlet.class, "framework");
ReflectionUtils.makeAccessible(frameworkField);
ReflectionUtils.setField(frameworkField, servlet, new NoAnalyticsAtmosphereFramework());
ServletRegistration.Dynamic atmosphereServlet =
servletContext.addServlet("atmosphereServlet", servlet);
atmosphereServlet.setInitParameter("org.atmosphere.cpr.packages", "com.myclient.theproduct.supervision.websocket");
atmosphereServlet.setInitParameter("org.atmosphere.cpr.broadcasterCacheClass", UUIDBroadcasterCache.class.getName());
atmosphereServlet.setInitParameter("org.atmosphere.cpr.broadcaster.shareableThreadPool", "true");
atmosphereServlet.setInitParameter("org.atmosphere.cpr.broadcaster.maxProcessingThreads", "10");
atmosphereServlet.setInitParameter("org.atmosphere.cpr.broadcaster.maxAsyncWriteThreads", "10");
servletContext.addListener(new org.atmosphere.cpr.SessionSupport());
atmosphereServlet.addMapping("/websocket/*");
atmosphereServlet.setLoadOnStartup(3);
atmosphereServlet.setAsyncSupported(true);
}
public class NoAnalyticsAtmosphereFramework extends AtmosphereFramework {
public NoAnalyticsAtmosphereFramework() {
super();
}
#Override
protected void analytics() {
// nothing
}
}
}
Don't ask me the reason of the NoAnalyticsAtmosphereFramework class, it could not work without.
Hope this will help you !

Resources