I received an e-mail a few minutes ago from an old friend. We used to work together at eDeploy, which has finally gone out of business, 2.5 years after they closed their doors. This was my last full time job and was also my favorite job of all time. I rode my bike to work, got to learn Java, wore shorts all the time, and thoroughly enjoyed our Friday lunches.
His questions were fairly simple:
- What is the best way to find a Java job/contract in Denver?
- Since you've had a lot more exposure to what technologies are being used more than others, is there somethings that I should brush up on while I've got the time off (i.e. struts, xslt, EJBs, . . .)?
I wrote a long answer and thought others might be able to benefit from it - so here it is (please add your own advice as you see fit):
What I'd recommend is to subscribe to the following local mailing lists:
RMIUG Jobs: RMIUG Jobs: http://rmiug.org/html/email_lists.html
DJUG Jobs: http://www.denverjug.org/resources/mailinglist.html
They get a fair amount of jobs that come across the wire, and I actually got 2 gigs last year through the RMIUG list. Struts is definitely one of the hottest skills, but I continue to get a lot of calls as a UI/Java Developer. Having the ability to write clean and pretty HTML as well write Java seems to be rare. To complement Struts, I'd focus on JSTL and JSP 2.0. You can't go wrong learning more about Ant and JUnit - I think a lot of people know JUnit, but not many put it on their resume.
You could check out my AppFuse application which uses all of these, as well as Hibernate (another hot one) for the persistence layer.
I started writing AppFuse when I wrote a couple chapters for Pro JSP last year. I use it on all my projects and it really helps accelerate the whole JSP/Struts/JUnit/Tomcat development cycle.
I'd also recommend reading a couple of really great books:
Java Development with Ant: a truly awesome book
Pro JSP: of course ;-)
J2EE Design and Development: I'm reading it right now
EJBs are a thing of the past - you might be able to get a gig doing them, but they're definitely waning. Rod Johnson (author of the 3rd book) wrote the Spring Framework as part of the book, and it's a pretty slick framework for taking the ugly out of J2EE. The project is getting a lot of press, and I hope to use Spring pretty soon to bind all my components together in AppFuse.
Above all else, I recommend starting to read weblogs (a.k.a. blogs), and if you like it, start your own. The best place to start reading them is JavaBlogs, JRoller and Java.net. I'm a committer on the open source project (Roller Weblogger) that runs JRoller. It's some damn slick blogging software. I host my site at KGBInternet for a measly $20/month and I get my own instance of Tomcat to screw up. Reading blogs is definitely the best way to stay on the bleeding edge of Java (and any other industry for that matter).
When I first added a Compression/GZip filter to AppFuse, I used the one from Roller, which I believe Lance found in this book. This has worked fairly well since I added it in July last year. When I discovered that there were issues with it on Resin, I chaulked it up as "no big deal" since I don't use Resin anyway. But yesterday, when I discovered that it stopped my apps from displaying my 403 <error-code> page, that was the last straw. I remembered seeing the "Two Servlet Filters Every Web Application Should Have" article on ONJava.com about a different implementation, so decided to download the source and try it out.
I quickly discovered that this Filter does work on Resin, so that's quite a bonus. I've had issues getting Roller to work on Resin with the Filter enabled, so I might have to replace Roller's CompressionFilter. However, I did still have to change a few things to convince this Filter to satisfy my needs.
Here are a few things I discovered about this GZIPFilter vs. Roller's CompressionFilter:
- Don't download the GZIPFilter from the article. There is a newer version of the code. Not much has changed, save for an almost completely re-written GZipResponseStream.java file. This one supposedly does better handling of large files.
- This Filter has the same problem I experienced with Roller's CompressionFilter: JSP pages don't finish rendering when running my Canoo WebTests. I'm assuming that this is because the buffer hasn't finished spitting out HTML. I ended up writing a new isGZIPSupported() method (in GZIPFilter.java) to do the check for GZip support. This allows my webtests to run smoothly by disabling the filter for HttpUnit.
- This Filter shares another issue that I found in the CompressionFilter yesterday. When my webapp returns an HttpServletResponse.SC_FORBIDDEN error code (from trying to access a method that denies the users role), the Filter suppresses the error and the user is not served up the 403 error page defined in my web.xml. To fix this, I overrode sendError() in GZIPResponseWrapper.java and added a check for this error code in the getWriter() method.
Overall, I'm pleased with this code because I love the concept of GZip Filtering, and now it's not causing any conflicts in my app or targeted appservers.
GZIPFilter.isGZIPSupported(HttpServletRequest):
private boolean isGZIPSupported(HttpServletRequest req) {
String browserEncodings = req.getHeader("accept-encoding");
boolean supported =
((browserEncodings != null) &&
(browserEncodings.indexOf("gzip") != -1));
String userAgent = req.getHeader("user-agent");
if (userAgent.startsWith("httpunit")) {
if (log.isDebugEnabled()) {
log.debug("httpunit detected, disabling filter...");
}
return false;
} else {
return supported;
}
}
|
GZIPResponseWrapper.sendError(int, java.lang.String):
public void sendError(int error, String message) throws IOException {
super.sendError(error, message);
this.error = error;
if (log.isDebugEnabled()) {
log.debug("sending error: " + error + " [" + message + "]");
}
}
|
GZIPResponseWrapper.getWriter():
public PrintWriter getWriter() throws IOException {
// If access denied, don't create new stream or write because
// it causes the web.xml's 403 page to not render
if (this.error == HttpServletResponse.SC_FORBIDDEN) {
return super.getWriter();
}
if (writer != null) {
return (writer);
}
|