I'm attempting to use HTTP Streaming with a servlet. Locally I use orion as a servlet container and it works fine, but on the test server, which runs JRUN 4.0, the output is buffered even when I call flush() on the output stream. Any thoughts on why the output is being buffered and what I can do to stop it?
OutputStream os = servletResponse.getOutputStream();
while (true)
{
//attempt to write to output before doing anything else. If browser has disconnected, an IOException will be thrown so nothing else will be done
os.write(".".getBytes());
os.flush();
String response = getData();
os.write(response.getBytes());
os.flush();
try
{
Thread.sleep(1000);
}
catch (InterruptedException e)
{
}
}
Related
I have an application that uses Spring Integration to send messages to a vendor application over TCP and receive and process responses. The vendor sends messages without a length header or an message-ending token and the message contains carriage returns so I have implemented a custom deserializer. The messages are sent as XML strings so I have to process the input stream, looking for a specific closing tag to know when the message is complete. The application works as expected until the vendor application is restarted or a port switch occurs on my application, at which time the CPU usage on my application spikes and the application becomes unresponsive. The application throws a SocketException: o.s.integration.handler.LoggingHandler : org.springframework.messaging.MessagingException: Send Failed; nested exception is java.net.SocketException: Connection or outbound has closed when the socket closes. I have set the SocketTimeout to be 1 minute.
Here is the connection factory implementation:
#Bean
public AbstractClientConnectionFactory tcpConnectionFactory() {
TcpNetClientConnectionFactory factory = new TcpNetClientConnectionFactory(this.serverIp,
Integer.parseInt(this.port));
return getAbstractClientConnectionFactory(factory, keyStoreName, trustStoreName,
keyStorePassword, trustStorePassword, hostVerify);
}
private AbstractClientConnectionFactory getAbstractClientConnectionFactory(
TcpNetClientConnectionFactory factory, String keyStoreName, String trustStoreName,
String keyStorePassword, String trustStorePassword, boolean hostVerify) {
TcpSSLContextSupport sslContextSupport = new DefaultTcpSSLContextSupport(keyStoreName,
trustStoreName, keyStorePassword, trustStorePassword);
DefaultTcpNetSSLSocketFactorySupport tcpSocketFactorySupport =
new DefaultTcpNetSSLSocketFactorySupport(sslContextSupport);
factory.setTcpSocketFactorySupport(tcpSocketFactorySupport);
factory.setTcpSocketSupport(new DefaultTcpSocketSupport(hostVerify));
factory.setDeserializer(new MessageSerializerDeserializer());
factory.setSerializer(new MessageSerializerDeserializer());
factory.setSoKeepAlive(true);
factory.setSoTimeout(60000);
return factory;
}
Here is the deserialize method:
private String readUntil(InputStream inputStream) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
String s = "";
byte[] closingTag = CLOSING_MESSAGE_TAG.getBytes(ASCII);
try {
Integer bite;
while (true) {
bite = inputStream.read();
byteArrayOutputStream.write(bite);
byte[] bytes = byteArrayOutputStream.toByteArray();
int start = bytes.length - closingTag.length;
if (start > closingTag.length) {
byte[] subarray = Arrays.copyOfRange(bytes, start, bytes.length);
if (Arrays.equals(subarray, closingTag)) {
s = new String(bytes, ASCII);
break;
}
}
}
} catch (SocketTimeoutException e) {
logger.error("Expected SocketTimeoutException thrown");
} catch (Exception e) {
logger.error("Exception thrown when deserializing message {}", s);
throw e;
}
return s;
}
Any help in identifying the cause of the CPU spike or a suggested fix would be greatly appreciated.
EDIT #1
Adding serialize method.
#Override
public void serialize(String string, OutputStream outputStream) throws IOException {
if (StringUtils.isNotEmpty(string) && StringUtils.startsWith(string, OPENING_MESSAGE_TAG) &&
StringUtils.endsWith(string, CLOSING_MESSAGE_TAG)) {
outputStream.write(string.getBytes(UTF8));
outputStream.flush();
}
}
the inbound-channel-adapter uses the ConnectionFactory
<int-ip:tcp-inbound-channel-adapter id="tcpInboundChannelAdapter"
channel="inboundReceivingChannel"
connection-factory="tcpConnectionFactory"
error-channel="errorChannel"
/>
EDIT #2
Outbound Channel Adapter
<int-ip:tcp-outbound-channel-adapter
id="tcpOutboundChannelAdapter"
channel="sendToTcpChannel"
connection-factory="tcpConnectionFactory"/>
Edit #3
We have added in the throw for the Exception and are still seeing the CPU spike, although it is not as dramatic. Could we still be receiving bytes from socket in the inputStream.read() method? The metrics seem to indicate that the read method is consuming server resources.
#Artem Bilan Thank you for your continued feedback on this. My server metrics seem to indicate that they deserialize method is what is consuming the CPU. I was thinking that the SendFailed error occurs because of the vendor restarting their application.
Thus far, I have been unable to replicate this issue other than in production. The only exception I can find in production logs is the SocketException mentioned above.
Thank you.
My RSS servlet uses try-with-resource for the OutputStream out of the HttpServletResponse and the writer for it. In some cases SomeException is thrown whilst generating the RSS document, in which case I need to return an HTTP status 500 to the client:
try (ServletOutputStream out = response.getOutputStream();
OutputStreamWriter writer = new OutputStreamWriter(out, "utf-8")) {
response.setContentType("text/xml");
// Generate RSS here
} catch (SomeException e) {
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
return;
}
However, by the time response.sendError() is called, the $out$ has already been closed and I get said IllegalStateException saying that the response has already been committed (closing the stream seems to commit the response automatically ).
If I move the initialization of out and writer outside of the try-block and close them in a finally-block (the pre-Java7 way), the error code gets sent correctly.
I was wondering whether there's a way to keep using try-with-resource and still be able to return error codes in case of an exception.
Thanks!
You don't need to close resources which you didn't create yourself. The container created the underlying OutputStream all by itself and is therefore also all by itself responsible for properly closing it. You should visualise it that the container has already put a try-with-resources around the servlet's doXxx() method. See also Should I close the servlet outputstream?
Differently put, the whole try-with-resources on OutputStream inside doXxx() is unnecessary.
Just do:
try {
// Generate RSS here
OutputStreamWriter writer = new OutputStreamWriter(response.getOutputStream(), "UTF-8")) {
response.setContentType("text/xml");
// Write RSS here.
} catch (SomeException e) {
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
}
Unrelated to the concrete problem, if you rethrow any checked exception as ServletException, then the container will also all by itself take care of the proper response code and message.
try {
// ...
} catch (SomeException e) {
throw new ServletException(e);
}
I have created a dynamic web project in eclipse.
It contains a Servlet ResidentApi.java and two java classes:GeoLocationDemo.java and Geolocation.java. I am calling GeoLocationDemo.java from my servlet and getting result in a ResultSet.But i am not getting any value in ResultSet.
When i ran same GeoLocationDemo.java separatly i am getting right results.I don't know servlet is able to call my java class or not but if it is then why i am not getting results.
I am having hard time debugging it.What i am doing is running .war file of this project every time on tomcat server and checking results there.Please suggest a good method to test it on eclipse.
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
response.setContentType("text/html");
PrintWriter out = response.getWriter();
ResultSet rs = null;
try{
GeoLocationDemo geo = new GeoLocationDemo(); //Here i created a new object
rs = geo.getResults(); //here i called a method of GeoLocation
}catch(Exception e){
// System.out.println(e);
out.write("<head><b You suck</b></head>");
}
out.write("<head><b>Congratulation! connected</b></head>"); //i am getting this output
try{
while(rs.next()){
String s = rs.getString("Details");
out.write("<head><b> "+s+ " </b></head>"); //not able to get this output
}
}catch(Exception e){
// System.out.println(e);
out.write("<head><b>You Built </b></head>");
}
out.close();
}
Don't put everything in a <head> tag! Open a body somewhere. Don't silently swallow any Exception you might be getting. Do remember to close() the ResultSet. Also, you should probably be returning all of your data in a List with a POJO.
out.write("<body>");
out.write("<b>Congratulation! connected</b><br/>");
try {
while (rs.next()) {
String s = rs.getString("Details");
out.write("<b> "+s+ "</b><br/>");
}
} catch (Exception e){
// System.out.println(e);
out.write("<b>" + e.getMessage() + "</b>");
e.printStackTrace(out);
} finally {
try {
out.close();
} catch (Exception ignored) {
}
try {
rs.close();
} catch (Exception ignored) {
}
}
configure remote debugging between your IDE and Tomcat server e.g. take a look on Remote debugging Tomcat with Eclipse
localize the problem - is the problem in GeoLocationDemo or in ResultSet or in output processing
p.s. do not close resources you never open - out.close(); - it is managed by servlet container
I am calling a web service from BlackBerry using J2ME code. When I try to open a connection using HttpConnection, it is checking only the GPRS connection. Now, I want to check the Wi-Fi connection and call a webservice through Wi-Fi.
The following code is my connection section. How to change the code for a Wi-Fi connection?
public boolean HttpUrl()
{
HttpConnection conn = null;
OutputStream out = null;
String url = "http://www.google.com";
try
{
conn = (HttpConnection) new ConnectionFactory().getConnection(url).getConnection();
if (conn != null)
{
conn.setRequestMethod(HttpConnection.POST);
conn.setRequestProperty("Content-Length", "application/x-www-form-urlencoded");
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
conn.setRequestProperty("User-Agent", "Profile/MIDP-2.0 Configuration/CLDC-1.0");
}
}
catch (Exception e)
{
return false;
}
finally
{
try
{
out.close();
}
catch (Exception e2)
{
}
}
//Only if exception occurs, we close the connection.
//Otherwise the caller should close the connection himself.
try
{
conn.close();
}
catch (Exception e1)
{
}
return true;
}
Check this way:
HttpConnection conn = null;
String URL = "http://www.myServer.com/myContent;deviceside=true;interface=wifi";
conn = (HttpConnection)Connector.open(URL);
source
Making Connections
Rafael's answer will certainly work if you know you'll only be using Wi-Fi.
However, if you only need to support BlackBerry OS 5.0 - 7.1, I would recommend that you do use the ConnectionFactory. Normally, you will not limit your code to only using one transport. You'll normally support (almost) any transport the device has, but you may want to code your app to choose certain transports first.
For example,
class ConnectionThread extends Thread
{
public void run()
{
ConnectionFactory connFact = new ConnectionFactory();
connFact.setPreferredTransportTypes(new int[] {
TransportInfo.TRANSPORT_TCP_WIFI,
TransportInfo.TRANSPORT_BIS_B,
TransportInfo.TRANSPORT_MDS,
TransportInfo.TRANSPORT_TCP_CELLULAR
});
ConnectionDescriptor connDesc;
connDesc = connFact.getConnection("http://www.google.com");
if (connDesc != null)
{
HttpConnection httpConn;
httpConn = (HttpConnection)connDesc.getConnection();
try
{
// TODO: set httpConn request method and properties here!
final int iResponseCode = httpConn.getResponseCode();
UiApplication.getUiApplication().invokeLater(new Runnable()
{
public void run()
{
Dialog.alert("Response code: " +
Integer.toString(iResponseCode));
}
});
}
catch (IOException e)
{
System.err.println("Caught IOException: "
+ e.getMessage());
}
}
}
}
will choose the Wi-Fi transport if Wi-Fi is available, but use the GPRS connection if it isn't. I think this is generally considered best practice for the 5.0+ devices.
Request Properties
This code
conn.setRequestProperty("Content-Length", "application/x-www-form-urlencoded");
is not right. Content-Length should be the size, in bytes, of your HTTP POST parameters. See an example here.
Threading
Remember that making network connections is slow. Do not block the user interface by running this code on the main/UI thread. Put your code into a background thread to keep the UI responsive while you request remote content.
I am writing an integration webservice which will consume various webservices from a couple different backend systems. I want to be able to parallelize non-dependent service calls and be able to cancel requests that take too long (since I have an SLA to meet).
to aid in parallel backend calls, I am using the ASYNC client apis (generated by wsimport using the client-side jax-ws binding alteration files)
the issue I am having is that when I try to cancel a request, the Response<> appropriately marks the request as canceled, however the actual request is not really canceled. apparently some part of the JAX-WS runtime actually submits a com.sun.xml.ws.api.pipe.Fiber to the run queue which is what actually does the request. the cancel on the Result<> does not prevent these PIPEs from running on the queue and making the request.
has anyone run into this issue or a similar issue before?
My code looks like this:
List<Response<QuerySubscriberResponse>> resps = new ArrayList<Response<QuerySubscriberResponse>>();
for (int i = 0; i < 10; i++) {
resps.add(FPPort.querySubscriberAsync(req));
}
for (int i = 0; i < 10; i++) {
logger.info("Waiting for " + i);
try {
QuerySubscriberResponse re = resps.get(i).get(1,
TimeUnit.SECONDS); // execution time for this request is 15 seconds, so we should always get a TimeoutException
logger.info("Got: "
+ new Marshaller().marshalDocumentToString(re));
} catch (TimeoutException e) {
logger.error(e);
logger.error("Cancelled: " + resps.get(i).cancel(true));
try {
logger.info("Waiting for my timed out thing to finish -- technically I've canceled it");
QuerySubscriberResponse re = resps.get(i).get(); // this causes a CancelledExceptio as we would expect
logger.info("Finished waiting for the canceled req");
} catch (Exception e1) {
e1.printStackTrace();
}
} catch (Exception e) {
logger.error(e);
} finally {
logger.info("");
logger.info("");
}
}
I would expect that all of these requests would end up being cancelled, however in reality they all continue to execute and only return when the backend finally decides to send us a response.
as it turns out this was indeed a bug in the jax-ws implementation. Oracle has issued a Patch (RHEL) against wls 10.3.3 to address this issue.