Request destroyed before initialization - servlet-listeners

I'm doing experiment with ServletRequestListener. I get the following output when i run the program. Some requests destroyed before initialized. why is that?
New request arrived to server :/projeDB/
Request destroyed : /projeDB/javax.faces.resource/primefaces.css.xhtml;jsessionid=2CDF29CD90D3EB1143D06AACAF7BA387
Request destroyed : /projeDB/javax.faces.resource/jquery/jquery.js.xhtml;jsessionid=2CDF29CD90D3EB1143D06AACAF7BA387
Request destroyed : /projeDB/javax.faces.resource/primefaces.js.xhtml;jsessionid=2CDF29CD90D3EB1143D06AACAF7BA387
New request arrived to server :/projeDB/javax.faces.resource/jquery/jquery.js.xhtml;jsessionid=2CDF29CD90D3EB1143D06AACAF7BA387
Request destroyed : /projeDB/javax.faces.resource/jquery/jquery-plugins.js.xhtml;jsessionid=2CDF29CD90D3EB1143D06AACAF7BA387
Request destroyed : /projeDB/javax.faces.resource/theme.css.xhtml
New request arrived to server :/projeDB/javax.faces.resource/primefaces.js.xhtml;jsessionid=2CDF29CD90D3EB1143D06AACAF7BA387
New request arrived to server :/projeDB/javax.faces.resource/jquery/jquery-plugins.js.xhtml;jsessionid=2CDF29CD90D3EB1143D06AACAF7BA387
New request arrived to server :/projeDB/javax.faces.resource/primefaces.css.xhtml;jsessionid=2CDF29CD90D3EB1143D06AACAF7BA387
New request arrived to server :/projeDB/javax.faces.resource/theme.css.xhtml
Request destroyed : /projeDB/javax.faces.resource/images/ui-icons_38667f_256x240.png.xhtml
New request arrived to server :/projeDB/javax.faces.resource/images/ui-icons_38667f_256x240.png.xhtml
My ServletRequestListener :
public class RequestListener implements ServletRequestListener {
#Override
public void requestDestroyed(ServletRequestEvent sre) {
System.out.println("New request arrived to server :" + ((HttpServletRequest) sre.getServletRequest()).getRequestURI()) ;
}
#Override
public void requestInitialized(ServletRequestEvent sre) {
System.out.println("Request destroyed : " + ((HttpServletRequest) sre.getServletRequest()).getRequestURI());
}
}

Haven't you switched the print statements in the methods? You print that the request has been destroyed in the requestInitialized() method and vice versa.

Related

TcpClient Only Returns First Result in Spring WebFlux Controller

I have an HTTP service exposing a GET endpoint that connects to a simple echo server via TCP. The HTTP service is running on Netty.
#RestController
public class OurTcpClient {
private Connection connection;
#GetMapping("echo1")
public Mono<String> echo(#RequestParam("value") final String value) {
this.connection.outbound()
.sendString(Mono.just(String.format("%04d", value.length()) + value)) // prepend length
.then()
.subscribe();
return this.connection.inbound()
.receive()
.asString()
.next();
}
#PostConstruct
public void init() {
this.connection = TcpClient.create()
.host("localhost")
.port(10002)
.wiretap(true)
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000)
.option(ChannelOption.SO_KEEPALIVE, true)
.connectNow();
}
}
My expectation is that I can query the service at, for example, http://localhost:8081/echo1?value=hi, as many times as I like, and receive "hi" back in each response. This works for the first request. The second request hangs indefinitely. If I then cancel the second request and attempt another, I get the following error:
{
"timestamp": "2020-04-13T18:56:40.221+0000",
"path": "/echo1",
"status": 500,
"error": "Internal Server Error",
"message": "Only one connection receive subscriber allowed."
}
Any help would be greatly appreciated.
In the example you use next()
return this.connection.inbound()
.receive()
.asString()
.next();
According to the Flux#next javadoc Emit only the first item emitted by this Flux, into a new Mono., then the subscription will be canceled.
In the context of Reactor Netty when you use next, timeout, take etc. operators that cancel the subscription this means that the connection will be closed.

Spring Integration two way communication with gps devices

We are using spring integration application for data receiption from gps devices. For current configuration we are able to receive data from device also respose sent back to device through same connection
current configuration is as
#SpringBootApplication
#IntegrationComponentScan
public class SpringIntegrationApplication extends SpringBootServletInitializer{
private Integer TIMEOUT=1000*60*10;
#Value("${TCP_PORT}")
private Integer TCP_PORT;
public static void main(String[] args) throws IOException {
ConfigurableApplicationContext ctx = SpringApplication.run(SpringIntegrationApplication.class, args);
System.in.read();
ctx.close();
}
#Bean
TcpNetServerConnectionFactory cf(){
TcpNetServerConnectionFactory connectionFactory=new TcpNetServerConnectionFactory(TCP_PORT);
connectionFactory.setSerializer(new CustomSerializerDeserializer());
connectionFactory.setDeserializer(new CustomSerializerDeserializer());
connectionFactory.setSoTimeout(TIMEOUT);
return connectionFactory;
}
#Bean
TcpInboundGateway tcpGate(){
TcpInboundGateway gateway=new TcpInboundGateway();
gateway.setConnectionFactory(cf());
gateway.setRequestChannel(requestChannel());
gateway.setRequestTimeout(TIMEOUT);
return gateway;
}
#Bean
public MessageChannel requestChannel(){
return new DirectChannel();
}
}
and message end point
#MessageEndpoint
public class Echo {
#ServiceActivator(inputChannel="requestChannel")
public byte[] echo(byte[] in,#SuppressWarnings("deprecation") #Header("ip_address") String ip){
//here we receive packet data in bytes from gps device
return "".getBytes();//string will contains expected result for device.
}
Above configuartion works fine for one way communication. but we want to implement two way communication. What we want after connection established between server and device we want to send message explicitely.To send command through server we dont know ip and port of device, so how can we send command through server to connected device.
I am trying following solution
created oubound channel adapter
#Bean
public TcpSendingMessageHandler tcpSendingMessageHandler() {
System.out.println("Creating outbound adapter");
TcpSendingMessageHandler outbound = new TcpSendingMessageHandler();
return outbound;
}
then created gateway for explicite message send, this will be called from service where we want to send data explicitely
#MessagingGateway(defaultRequestChannel="toTcp")
public static interface tcpSendService {
public byte [] send(String string);
}
After calling gate way following service activator invoked where we are setting connection ip and port, these ip and ports will be from connection established while receiving data from device
#ServiceActivator(inputChannel="toTcp", outputChannel="fromTcp")
public String send(String in){
System.out.println(new String(in));
TcpNetClientConnectionFactory factory = new TcpNetClientConnectionFactory(ip_extracted_from_inbound_connection, port_extarcted_from_inbound_connection);
factory.start();
tcpSendingMessageHandler.setConnectionFactory(factory);
return in;
}
// for ip and port extraction i am using following service which is inbound sevice
#ServiceActivator(inputChannel="requestChannel")
public byte[] echo(byte[] in,#Header("ip_address") String ip){
System.out.println(new String(in)+ " ; IP : "+ip);
for (String connectionId : factory.getOpenConnectionIds()) {
if(!lastConection.contains(ip))
lastConection = connectionId;
}
return "hello".getBytes();
}
For service activator i am setting new TcpNetClientConnectionFactory every time service called. Ip and port are extracted from TcpNetServerConnectionFactory. whenever device connects with server i am saving its connection ip and port, using these ip and port for data transmission through server but i am getting connection timeout issue.
Kindly help me out and suggest me a solution over it.
Thank you.
Replace the gateway with a pair of Collaborating Outbound and Inbound Channel Adapters.
In order to send arbitrary messages to a connection, you must set the ip_connectionId header.
The challenge, though, is how to direct the reply to the gateway. You would need to capture the replyChannel header from the request and, when a reply is received for that ip_connectionId, set the replyChannel headers.
This will only work, though, if you have only one request/reply outstanding to each device at a time, unless there is some data in the reply that can be used to correlate it to a request.
Another challenge is race conditions, where the device and the server initiate a request at the same time. You would need to look at data in the inbound message to see if it's a request or reply.

Is there a helper method to extract origin host from request (to build a link)

I receive request via a router :
#Bean
public RouterFunction<ServerResponse> routerFunction() {
return nest(path(API_PATH), route(GET("/"), indexHandler::getIndex));
}
handle by a method :
public Mono<ServerResponse> getIndex(ServerRequest request) {
...
}
I need to extract the url use to request the service, I have different cases, sometimes request are direct to service, sometimes request go through proxy (and add X-Forwarded-Path,X-Forwarded-Path headers).
Is there a helper method, to extract this details from ServerRequest object ?

Could Http server return error code before POST body is sent?

If a Http server is not reachable, and Http client is trying to send a POST request to the server, will the Post content ever have the opportunity to be sent or no (say error code come back and the code will not be executed)?
More specifically, I have special logic in writeTo function, I would like to know if it is executed or not if Http server is not reachable.
public interface HttpEntity {
boolean isRepeatable();
boolean isChunked();
long getContentLength();
Header getContentType();
Header getContentEncoding();
InputStream getContent() throws IOException, IllegalStateException;
void writeTo(OutputStream var1) throws IOException;
boolean isStreaming();
void consumeContent() throws IOException;
}

Not getting response with Http Async Client

I am stuck with this weird situation where sometimes my HTTP requests don't go out or I don't get a HTTP response to my request sporadically. My application makes several (100s) http requests to other 3rd party service periodically most of which work absolutely fine.
I use the CloseableHttpAsyncClient (Version 4.0) with a custom HttpRequestIntercerptor and HttpResponseInterceptor. These were mainly added for debugging purpose with the RequestInterceptor is the last interceptor in the chain and the ResponseInterceptor is the first one. The idea was to log each http request at the last stage before it sends the actual request and to log each http response when it is first received.
I have the following pattern to setup the async client:
HttpAsyncClientBuilder asyncClientBuilder = HttpAsyncClientBuilder.create();
asyncClientBuilder.addInterceptorLast(new MyHttpRequestInterceptor());
asyncClientBuilder.addInterceptorFirst(new MyHttpResponseInterceptor());
IOReactorConfig reactorConfig = IOReactorConfig.DEFAULT;
reactorConfig.setConnectTimeout(5 * 60 * 1000); // 5 mins
reactorConfig.setSoTimeout(5 * 60 * 1000); // 5 mins
asyncClientBuilder.setDefaultIOReactorConfig(reactorConfig);
System.setProperty("http.maxConnections", "100");
this.asyncHttpClient = asyncClientBuilder.useSystemProperties().build();
this.asyncHttpClient.start();
To make the request I do:
HttpGet httpGet = new HttpGet("some url");
asyncHttpClient.execute(httpGet, new AsyncHTTPResponseHandler(requestMetadata));
Here is my AsyncHTTPResponseHandler class:
class AsyncHTTPResponseHandler implements FutureCallback<HttpResponse> {
// local copy of the request for reference while processing the response.
private RequestMetadata requestMetadata;
public AsyncHTTPResponseHandler(final RequestMetadata requestMetadata) {
this.setRequestMetadata(requestMetadata);
Thread.currentThread().setUncaughtExceptionHandler(new HttpUncaughtExceptionHandler(requestMetadata));
}
#Override
public void cancelled() {
logger.error("AsyncHTTPResponseHandler#Http request id: {} cancelled",
requestMetadata.getRequestId()));
}
#Override
public void completed(HttpResponse response) {
logger.debug("Received HTTP Response for request id: {}",
requestMetadata.getRequestId());
//handleHttpResponse(requestMetadata, response);
}
#Override
public void failed(Exception e) {
logger.error("AsyncHTTPResponseHandler#Error in Http request id: " + requestMetadata.getRequestId(), e);
}
}
Based on this setup, I see the following cases based on my interceptors logs:
1. My application http request triggers an asyncclient HttpRequest and I get the HttpResponse -- Success.
2. My application http request triggers an asyncclient HttpRequest (the interceptor logs it) and I don't get the HttpResponse for this request --- Don't know why?
3. My application http request does not trigger an asyncclient HttpRequest (the interceptor does not log it) and I don't get the HttpResponse for this request --- Don't know why?
Any tips or suggestions on what I can do fix this or debug this problem further?
Thanks!!
So, thought I will share my findings and solution here.
We were experiencing symptoms similar to this bug: https://issues.apache.org/jira/browse/HTTPASYNC-79
If you enable DEBUG logging for "org.apache.http.impl.nio" package, then you can see the exchanges. Note: The logs will be very verbose.
The issue was resolved by upgrading the HttpAsyncClient library from 4.0 to 4.0.2. I have also enabled socket and Connection timeouts. You should see timeout exceptions in the log files with this.
Here is how my HttpAsyncClient instance looks now:
HttpAsyncClientBuilder asyncClientBuilder = HttpAsyncClientBuilder.create();
asyncClientBuilder.addInterceptorLast(new MyHttpRequestInterceptor());
asyncClientBuilder.addInterceptorFirst(new MyHttpResponseInterceptor());
// reactor config
IOReactorConfig reactorConfig = IOReactorConfig.custom()
.setConnectTimeout(TIMEOUT_5_MINS_IN_MILLIS)
.setSoTimeout(TIMEOUT_5_MINS_IN_MILLIS).build();
asyncClientBuilder.setDefaultIOReactorConfig(reactorConfig);
// request config
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(TIMEOUT_5_MINS_IN_MILLIS)
.setConnectionRequestTimeout(TIMEOUT_5_MINS_IN_MILLIS)
.setSocketTimeout(TIMEOUT_5_MINS_IN_MILLIS).build();
asyncClientBuilder.setDefaultRequestConfig(requestConfig);
// connection config
ConnectionConfig connectionConfig = ConnectionConfig.custom()
.setMalformedInputAction(CodingErrorAction.IGNORE)
.setUnmappableInputAction(CodingErrorAction.IGNORE)
.build();
asyncClientBuilder.setDefaultConnectionConfig(connectionConfig);
System.setProperty("http.maxConnections", "100");
System.setProperty("http.conn-manager.timeout", "300000"); // 5 mins
this.asyncHttpClient = asyncClientBuilder.useSystemProperties().build();