0

I'm stuck at exception

java.lang.IllegalArgumentException: Invalid token character '/' in token "gml/2.1.2"
at org.springframework.http.MediaType.checkToken(MediaType.java:354)

I'm using Spring Integration 3.0 RC1 and http outbound gateway to send request to Geoserver. Unfortunately the exception is thrown from inside of org.springframework.web.client.RestTemplate which I cannot override (outbound gateway manages it), so it's to deep for me to change the headers by some HeaderMapper as I've already tried. I'm also unable to change the request header coming from external site, as it's produced by Geoserver.

The error cause header is: Content-Type=[text/xml; subtype=gml/2.1.2]

Please give me some clues if you have one, I'm struggling with it for several days now.

My spring integration setup:

<util:list id="wfsProxyMessageConverterList">
    <bean class="xxx.StringWfsHttpMessageConverter" />
    <bean class="xxx.ByteArrayWfsHttpMessageConverter" />       
</util:list>

<int:channel id="wfsRequest"></int:channel>
<int:channel id="wfsResponse"></int:channel>

<bean id="wfsHeaderMapper" class="xxx.WfsHeaderMapper" />

<int-http:inbound-gateway id="wfsInboundGateway" supported-methods="POST"
    request-channel="wfsRequest" reply-channel="wfsResponse"
    path="/gisproxy/wfs" reply-timeout="10000"  
    header-mapper="wfsHeaderMapper"         
        message-converters="wfsProxyMessageConverterList"

    />

<int-http:outbound-gateway id="wfsOutboundGateway"
    request-channel="wfsRequest" reply-channel="wfsResponse"
    url="#{geoserverConfig.url}/wfs"
    http-method="POST" charset="UTF-8" reply-timeout="10000"
    expected-response-type="java.lang.String"
    message-converters="wfsProxyMessageConverterList"
    header-mapper="wfsHeaderMapper"

    encode-uri="false" request-factory="apacheCommonsHttpClient">               
</int-http:outbound-gateway>

Cheers, denu

--- edit: added stack trace ---

SEVERE: Servlet.service() for servlet [core] in context with path [/myapp] threw exception [Request processing failed; nested exception is org.springframework.integration.MessageHandlingException: HTTP request execution failed for URI [https://xx.xxx.xxx.xx:8181/geoserver/wfs]] with root cause
java.lang.IllegalArgumentException: Invalid token character '/' in token "gml/2.1.2"
at org.springframework.http.MediaType.checkToken(MediaType.java:354)
at org.springframework.http.MediaType.checkParameters(MediaType.java:374)
at org.springframework.http.MediaType.<init>(MediaType.java:335)
at org.springframework.http.MediaType.parseMediaType(MediaType.java:722)
at org.springframework.http.HttpHeaders.getContentType(HttpHeaders.java:305)
at org.springframework.web.client.HttpMessageConverterExtractor.getContentType(HttpMessageConverterExtractor.java:113)
at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:84)
at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:687)
at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:673)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:491)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:460)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:409)
at org.springframework.integration.http.outbound.HttpRequestExecutingMessageHandler.handleRequestMessage(HttpRequestExecutingMessageHandler.java:372)
at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:142)
at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:73)
at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:115)
at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:102)
at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:77)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:178)
at org.springframework.integration.core.MessagingTemplate.doSend(MessagingTemplate.java:304)
at org.springframework.integration.core.MessagingTemplate.doSendAndReceive(MessagingTemplate.java:335)
at org.springframework.integration.core.MessagingTemplate.sendAndReceive(MessagingTemplate.java:255)
at org.springframework.integration.gateway.MessagingGatewaySupport.doSendAndReceive(MessagingGatewaySupport.java:234)
at org.springframework.integration.gateway.MessagingGatewaySupport.sendAndReceiveMessage(MessagingGatewaySupport.java:208)
at org.springframework.integration.http.inbound.HttpRequestHandlingEndpointSupport.actualDoHandleRequest(HttpRequestHandlingEndpointSupport.java:478)
at org.springframework.integration.http.inbound.HttpRequestHandlingEndpointSupport.doHandleRequest(HttpRequestHandlingEndpointSupport.java:380)
at org.springframework.integration.http.inbound.HttpRequestHandlingMessagingGateway.handleRequest(HttpRequestHandlingMessagingGateway.java:101)
at org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter.handle(HttpRequestHandlerAdapter.java:49)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:925)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:920)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:827)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:647)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:801)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:118)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:54)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:183)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:259)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.springframework.orm.hibernate4.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:152)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1023)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:724)
denu
  • 2,170
  • 2
  • 23
  • 28
  • 2
    FWIW That's an invalid header. http://www.w3.org/Protocols/rfc1341/4_Content-Type.html (Specifically special characters can only exist in quoted strings) Can you raise it with Geoserver as a bug? – Taylor Dec 11 '13 at 02:22
  • Hi, I've found an existing issue on Geoserver's JIRA. Until it's fixed I have to find some workaround in spring integration. http://jira.codehaus.org/browse/GEOS-4011 – denu Dec 13 '13 at 21:04
  • @denu did you find answer for this? – sunleo Aug 10 '17 at 09:28

2 Answers2

3

According to RFC 2616 (and as Taylor said according to RFC 1341) it is an invalid value for Content-Type HTTP header. So you should have deal with Geoserver anyway.

However, let's try to find a workaround to make your application working.

You have gone with right way using a custom implementation of DefaultHttpHeaderMapper. In this case you should exclude Content-Type header from inbound mapping - DefaultHttpHeaderMapper#setInboundHeaderNames - list all desired HTTP header name, but not Content-Type. You can see all supported headers from DefaultHttpHeaderMapper.HTTP_REQUEST_HEADER_NAMES constant (source code).

Then you should override DefaultHttpHeaderMapper#toHeaders, invoke super.toHeaders and take care of Content-Type, but using HttpHeaders.getFirst("Content-Type")

Of course, those all are needed, if you really are interested in Content-Type. If not, it's just enough to provide mapped-request-headers attribute with others headers names, or just a trick - mapped-request-headers="-" to suppress all request headers.

Community
  • 1
  • 1
Artem Bilan
  • 113,505
  • 11
  • 91
  • 118
  • Hi, thanks for reply! I've did like you wrote, but it seems to never go into my custom header mapper with response message (debugger steps in only to request message). You can also see it on stack trace I've attached - MediaType.checkToken is called directly from HttpMesssageConverterExtractor.getContentType... Am I doing something wrong? – denu Dec 13 '13 at 20:59
  • Sorry, for delay. We were releasing :-). So, I see your issue now. Looks like you should remove `expected-response-type="java.lang.String"` from your configuration. And return the response as is and conevert it to String after `` – Artem Bilan Dec 18 '13 at 10:52
0

I came up with this solution:

class WfsRestTemplate extends RestTemplate {
    @Override
    protected <T> T doExecute(URI url, HttpMethod method, RequestCallback callback, final ResponseExtractor<T> responseExtractor) throws RestClientException {
        return super.doExecute(url, method, callback, response -> {
            String contentType = response.getHeaders().getFirst("Content-Type");
            if (contentType.startsWith("text/xml")) response.getHeaders().setContentType(MediaType.TEXT_XML);
            return responseExtractor.extractData(response);
        });
    }
}
no id
  • 1,642
  • 3
  • 24
  • 36