Skip to content

Lesson learned: copying bytes from an OutputStream to an InputStream in Weblogic 8

A few weeks back, I posted about calling one servlet from another, passing a multipart/form-data for submission. I ended up using an HttpURLConnection and POSTing to the second servlet. My target platform was Weblogic 8 on Solaris 8, but I was developing on Windows Server 2003; both had Weblogic running on a Java 1.4 platform.

I set both the doOutput and doInput properties of the connection to true, so I can first post the needed data and then read the response, which I can parse and pass on to the user. Here’s the setup:

    URL url = new URL("http://localhost/myws/myservlet");
    URLConnection con = url.openConnection();
    HttpURLConnection conn = (HttpURLConnection)con;
    conn.setDoOutput(true);
    conn.setDoInput(true);
    conn.setRequestProperty("Content-Type", request.getHeader("Content-Type"));
    conn.setRequestProperty("Cookie", request.getHeader("Cookie"));
    BufferedInputStream bis = new BufferedInputStream(request.getInputStream());
    BufferedOutputStream bos = new BufferedOutputStream(conn.getOutputStream());

I set the Cookie property so that the user does not have to reauthenticate to the second servlet.

However, when I was reading from the first servlet’s InputStream and writing to the second servlet’s OutputStream, I encountered some issues. The below code ran perfectly fine in the development environment, but in the production environment, the file being transferred was corrupted. The corruption happened in a number of ways, actually. At first, the file was about twice the size. Then, after fiddling a bit and moving the bis.close() and bos.close() closer to the write/read, I was able to get the file to be smaller than the posted file. However, it was a zip file and was still corrupt.)

    byte[] data = new byte[1024];
    int res = bis.read(data);
    while (res != -1) {
        bos.write(data);
        res = bis.read(data);
    }
    bos.flush();
    // other stuff, like getting response code
    bis.close();
    bos.close();

You can see that I’m double buffering the InputStream here, first with the BufferedInputStream, and then with my byte array, data[]. That’s apparently unnecessary; I don’t know where I got the idea. It actually leads to loss of data on the Solaris box.

Luckily, the Java Cookbook (and for that matter, the I/O section of the Java Tutorial) suggested code similar to this:

    int res;
    while ((res = bis.read()) != -1) {
        bos.write(res);
    }
    bis.close();
    bos.close();

This code works on both Windows and Solaris. I’m a bit mystified as to why the first byte transfer method worked on Windows but not Solaris, and I thought I’d post this so that any other folks struggling with the same problem don’t endure the debugging that I did.

Building a Full-Text Search Engine from Open Source Components

A friend and former colleague did a presentation a few months ago about “Building a Full-Text Search Engine from Open Source Components”. The slides are up. From the abstract:

In addition to the many useful open source applications that are available ready-to-run, there are quite a few open source APIs out there that are just crying out to be combined in new, useful, and interesting ways. By “just” writing a few lines of code to join them together it should be possible to build a new application that has a unique set of features.

Calling one servlet from another

So, I’m building a RESTful web service for a client, which is going to accept a large (60 mbish) file and a set of parameters that are attributes of the file, using the multipart/form-data enctype. The idea is to have this service be available for external programs to post to, but to also provide a nice web interface. I built another servlet which generates the usable user interface (the UI servlet), and am now having trouble pushing the data over to the RESTful servlet. After the RESTful service is called, the UI servlet needs to ensure that any errors are understandable to the user.

It looks like there are a couple of options:

1. Use RequestDispatcher to hand the request entirely over to the service. This is easy, but it means that the service now needs to return a human readable response, or you need to insert a filter to provide one.

1a. Have the RESTful service take a parameter which indicates whether its caller is another program or a human being, and use the RequestDispatcher from the UI servlet.

1b. Have no UI servlet at all, but just have the RESTful servlet be able to generate a nice user interface (or redirect to a pleasant looking JSP) via a given parameter.

2. Use the URL and HttpURLConnection objects to have the UI servlet post to the RESTful servlet just as you’d post to any other remote resource on the internet with java. This seems to work ok (I think), but requires (I also think) an absolute URL and also requires a bit of I/O to push the stream of bytes from the UI servlet to the RESTful servlet.

I can’t think of any other ways to solve this problem, and the only other solution that searching turned up is a no-no in modern servlet engines.

Web calendars: jwebcalendar and FlatCalendarXP

Just a quick note. I just spent a few days looking at web calendars for a client. In particular, they wanted to show a 12 months view, rather than the more typical month at a time view. It’s in a java environment.

Stay away from jwebcalendar. Hasn’t been developed for a few years, and even though the feature set looks great and the screen shots look gorgeous, I wasn’t able able to get it to run (in tomcat 4 or tomcat 5). After putting in some log statements, and learning that you needed to specify the xsl and xml locations on the url line (like so: localhost:8080/jwebcalendar/calendar?LAYOUT=form.url&XSL=webcalendar.form.url.xsl&XSLbase=./data/webcalendar/xsl/&XML=webcalender.form.url.vm.xml&XMLbase=./data/webcalendar/xml/&XMLfilter=.xml&HTMLbase=&TITLE=PPres) I ended up seeing this error message:

Error org.apache.xmlbeans.XmlException: error: Element type “input” must be foll owed by either attribute specifications, “>” or “/>”. org.apache.xmlbeans.XmlException: error: Element type “input” must be followed b y either attribute specifications, “>” or “/>”. at org.apache.xmlbeans.impl.store.Root$SaxLoader.load…

Since I’d burned enough time, I didn’t follow the path any further. Major bummer, as it seemed like it would be a good fit.

After that, we looked at other calendar systems, and FlatCalendarXP seemed to fit the bill. It’s payware (for commercial software) but it has an elegant API and has worked well so far. Recommended.

BJUG last night: breaking it down

OK, here’s a grabbag of links and info regarding my talk last night (links and powerpoint available here). I was interested to know how many folks had actually worked on an internationalized application. (I18n is one of those APIs that you ignore until you need it, and then you absolutely have to have it.) Here are some rough numbers, based on a quick survey of hands. Out of a crowd of 25, about 5 people had used i18n. Of those, 3 had used it with web applications, and one with a J2SE application (I think the last person had used i18n with C). 3 of them had supported European languages and three had supported Asian languages.

I was emphasizing how important it was to pull out all the strings to be displayed to properties files, so they could be localized. A few folks in the audience mentioned that eclipse has support for this–out of the box for java classes, and with a plugin for jsps. (If you are reading this and know the name of the plugin, please comment; I did some googling and couldn’t find any jsp plugins that claimed an ‘Extract Strings’ capability.)

One person asked if we encountered issues with translating plurals, like house/houses. I hadn’t seen that problem with the application I worked upon, but was pretty sure that the java class libraries supported a solution. That solution is ChoiceFormat.

When I mentioned that we used Excel spreadsheets as our transfer format for slinging around translated strings, one of the other folks, who spent five years supporting a java application that was internationalized (he had some war stories), mentioned the XLIFF, an XML variant that is used in several translation editors. If you’re planning to do a lot of translation, you might want to take a look.

The talk after mine was an interesting discussion of SOA by Glen Coward. It was a rather discombobulating mix of an extremely high level look at the SOA landscape, complete with TLAs galore, and an extremely low level example of a rich client in Flex talking to two web services, one built with Axis on JBoss, and the other built with MS.NET deployed on Mono. The demo went poorly, as demos tend to do, but it was enough to whet my appetite to look a bit more closely at SOA.

In addition, as you’d expect from an employee of Novell, he was interested in delineating the differences between open source software and commercial software in a corporate environment, and where each made sense. His point was that in quickly changing areas, corporate software made sense, because of productivity gains that commercial IDE support makes available. In addition, deep integration (read, anything to do with backend legacy systems) is probably going to require commercial software. He didn’t specify why, but I’d guess that specialized backend integration is primarily going to continue to be commercial software for a number of reasons: it’s not sexy, it requires the backend system to test (not often available for the average hacker), and there are intellectual property issues. What Glen didn’t make explicit, but I will, is where that leaves open source–smack dab in the middle, gluing together all the applications. You know, like Apache and JBoss and Tomcat (among many others) already do.

As usual, I learned something at BJUG. And you can’t beat free pizza.

BJUG Localization talk

I’m giving a talk tomorrow (Thursday) in Boulder at BJUG at 6:00. The topic will be “Internationalization and Localization in the Real World”:

This is not another rehash of the Internationalization Trail fromthe Java Tutorial website. Rather, Dan examines one website that is supporting a large number of locales in the real world and looks at how i18n and l10n were implemented in the real world. This includes the nuts and bolts of loading multi character data, framework tools that helped, how users were associated with locales, what parts of the i18n API were not used, and issues to be aware of.

Afterwards, there will be pizza and pop, then a talk about Services Oriented Architecture. Hope to see you there.

Dropping the .com from package names

Dion wonders whether you need fully qualified package names on your java packages. For instance, is code that I write with this package declaration: package com.mooreds.foo; that much better than package mooreds.foo;?

Given that there are no other mooreds MLDs (from a search at network solutions):

mooreds.net is available.
mooreds.org is available.
mooreds.info is available.
mooreds.tv is available.
mooreds.us is available.
mooreds.cc is available.
mooreds.name is available.
mooreds.bz is available.
mooreds.co.uk is available.
mooreds.de is available.
mooreds.be is available.
mooreds.co.nz is available.
mooreds.at is available.
mooreds.com is unavailable.

I think the answer is that it doesn’t matter very much right now. And the chances of it mattering in the future are slim. I’d have to write some code with the same classname as another ‘mooreds’ packager, and want to import that code. Improbable, but possible. And if this situation arose, I’d have to rename my class, use a different package name (after all, packages don’t have to be meaningful) or use a different class.

What are the benefits of leaving off the com. declaration? Well, it saves everyone who wants to use it four characters of typing per import (those who don’t use auto importers). Four characters!

So, it’s safe to say that package mooreds.foo; and package com.mooreds.foo; probably won’t hurt anything, but given the cost benefit analysis, I can’t see why anyone wouldn’t use the full package declaration: package com.mooreds.foo; .

Now, if someone is using a domain they don’t own, well, that’s just braindead. 15$ and a credit card will get you a domain name. If you can’t afford that, then choose a TLD of your own creation; package lalala.mooreds.foo; won’t collide with anyone who is following the spec, and has an even smaller chance of colliding with someone who isn’t than just dropping the TLD.

In a different vein, I used to give an unusual name for restaurant waitlists, but oftne when they called out ‘Archibald’ I wasn’t attuned to it like I was to ‘Dan’ and more often than not, I missed my seating. Similarly, if you use a domain that someone else owns as your package name, well, you’re looking for trouble that you don’t really need to. I mean, really, isn’t software hard enough?