I’ve got an application deployed on Tomcat 5.0.28 that, when in production, uses log4j with the SMTP appender to send relevant debug / error messages via email. Soon after deploying the application I began receiving messages from the application which contained this stack trace:
java.io.IOException: ClientAbortException: java.net.SocketException: Connection reset by peer: socket write error at org.apache.coyote.tomcat5.OutputBuffer.doFlush(OutputBuffer.java:331) at org.apache.coyote.tomcat5.OutputBuffer.flush(OutputBuffer.java:297) at org.apache.coyote.tomcat5.CoyoteOutputStream.flush(CoyoteOutputStream.java:85) at sun.nio.cs.StreamEncoder$CharsetSE.implFlush(Unknown Source) at sun.nio.cs.StreamEncoder.flush(Unknown Source) at java.io.OutputStreamWriter.flush(Unknown Source) at java.io.BufferedWriter.flush(Unknown Source)....
The stack trace isn’t anything special: you’ll get a ClientAbortException whenever the HTTP client on the other end closes the connection prematurely (ie: before Tomcat has a chance to complete the flush of information to the output stream). The problem is that it pollutes your log file, or in my case, my inbox because I was receiving an email every time one of these errors occurred. My log4j configuration file looked something like this:
log4j.rootCategory=ERROR, SMTPAPPENDER
log4j.appender.SMTPAPPENDER.To=me@mydomain.com
log4j.appender.SMTPAPPENDER.layout=org.apache.log4j.PatternLayout
log4j.appender.SMTPAPPENDER=org.apache.log4j.net.SMTPAppender
log4j.appender.SMTPAPPENDER.Subject=[my app] ERROR
log4j.appender.SMTPAPPENDER.BufferSize=512
log4j.appender.SMTPAPPENDER.From=errors@mydomain.com
log4j.appender.SMTPAPPENDER.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
log4j.appender.SMTPAPPENDER.SMTPHost=localhost
which, in log4j parlance, means that I want any messages that are of type ERROR or FATAL sent to me via email. Instead I should have started it off with this:
log4j.rootCategory=FATAL, SMTPAPPENDER
log4j.category.com.mycompany=ERROR, SMTPAPPENDER
...
which translated means that I want any FATAL errors in any package sent to me via the SMTPAPPENDER but any messages of type ERROR or FATAL in the package com.mycompany sent to me as well. This effectively cuts out the unnecessary sending of ClientAbortException messages, while still generating the messages that I want to receive.
(Note: if your problem isn’t with log4j, but instead with your Tomcat log files, check out the debug settings in Server, Service, Engine and Host elements of your Tomcat conf\server.xml.)
I haven’t worked on my wife’s recipe site in ages. Originally written as an experiment with JSP and Java, I think my mom and Karen are the only people that use it (which is fine with me). In any case, I recently moved it to a new host and saw a weird issue pop up in catalina.out where any INSERT, UPDATE or DELETE statements were erroring out with the message:
java.sql.SQLException: Can not issue data manipulation statements with executeQuery()
Turns out that earlier versions of the MySQL JDBC driver allowed you to run INSERT / UPDATE / DELETE statements using the executeQuery() method of the PreparedStatement class, which violated the JDBC specification, but worked nonetheless. The newer versions are JDBC compliant and don’t allow that behavior, which causes the above mentioned SQL exception. More from the MySQL forums.
A search for ‘tomcat 5 outofmemory windows‘ returns about 2000 hits, not one of them shows you how can increase the amount of memory allocated to Tomcat via the Apache Tomcat Properties applet when running on Windows (some point to this Tomcat configuration document which seems to be a bit out of date). Start –> Programs –> Apache Tomcat 5.0 –> Configure Tomcat –> Java. The “Initial memory pool” corresponds to the JVM -Xms option (~ initial Java heap size), the “Maximum memory pool” corresponds to the JVM -Xmx option (~ maximum Java heap size) and the “Thread stack size” corresponds to the JVM -Xss option. The picture book follows:
You can read more about the non-standard options on java.sun.com.
Unfortunately we’re still using Windows on our servers at work, the last application I deployed didn’t have IIS installed on it (yay!), which means no local SMTP service. I needed a local SMTP server so I installed Apache James (I know, it’s probably overkill, but we might use some of it’s other features later). Anyway, buried deep in the SMTP Virtual Server properties applet in IIS is the ability to configure the server to send all email through another server; in IIS parlance this is called a ‘smart host‘. James (love the name btw) doesn’t have a ‘smart host’ option property sheet, but you can get the same functionality by using the <gateway> and <gatewayPort> elements of config.xml (buried in $james_install/apps/james/SAR-INF/config.xml). Read up on the options under RemoteDelivery.
The guys at TSS did a pretty indepth interview with Doug Cutting (who wrote Lucene and is now involved in the Nutch project). You can read the transcript here; there’s video there somewhere, I just couldn’t find it.
Donuld Knuth was on the Morning Edition this morning, you can still catch it via Windows Media Player or Real Player. He’s a real character (he leaves his bike helmet on inside because… eventually he’ll have to put it back on anyway).
My latest project at work launched a couple weeks ago, unfortunately there isn’t much to look at, but it’s not like I’m a Flash developer, so unless I start writing Windows apps, no one will ever be able to see my work anyway. Alas, a major portion of the project involved consolidating some business logic behind a SOAP API (I’ll go into that some other time). We were supposed to be moving our front end to ASP.NET but at the last minute, the ASP.NET migration didn’t happen so we ended up needing something that ASP could use as well, which meant REST. With the business logic wrapped up behind business delegates, all that was needed as a Servlet Filter to map requests for /myapp/xml to a Struts Action class, which invoked the business delegates and then returned XML to the client. Now on the SOAP end of things (Axis embedded in Tomcat), I didn’t have to deal with XML (Axis handles all the XML serialization and deserialization). But with REST you’re in conundrum: do you create toXML() methods on all of your JavaBeans? do you put the JavaBean or collection of beans in the Request scope and then generate the XML using JSP? Those options all seemed error prone and harder to test. I looked at JAXB (makes more sense when you have XML that you want to turn into a JavaBean) and Castor (same thing) but finally decided on using Betwixt, a Jakarta Commons library that provide a simple way of turning a JavaBean into XML. The end result looked something like this:
public class RESTAction extends DispatchAction {
public ActionForward doSomething(...) {
MyBean bean = BusinessLogic.getBean();
response.setContentType("text/xml");
OutputStream sos = response.getOutputStream();
BeanWriter beanWriter = new BeanWriter(sos);
BindingConfiguration config = beanWriter.getBindingConfiguration();
config.setMapIDs(false);
beanWriter.enablePrettyPrint();
String declr = "<?xml version='1.0' encoding='UTF-8' ?>";
beanWriter.writeXmlDeclaration(declr);
beanWriter.write("mybean", bean);
beanWriter.flush();
beanWriter.close();
return null;
}
}
which when combined with this action mapping:
<action
path="/xml"
type="com.mycompany.web.actions.RESTAction"
name="xmlForm"
scope="request"
parameter="method"
validate="false">
<forward name="error" path="/WEB-INF/views/xml/error.jsp" />
</action>
is invoked like so:
http://myserver/myapp/xml?method=doSomething
I’m not 100% sold on this as the “way”, but I do like how simple Betwixt is. If you’ve got a different idea, comment away.
Found in my server logs today:
"Mozilla/5.0 (Win32; U; FreeBSD 5.X i686; tw-TW; rv:1.0.0; hi, Mom) Gecko/20040604"
Now with 50% less caffeine!