tags:

views:

50

answers:

2

I need to load and process a template in freemarker. I am using a piped stream to read back the generated result by freemarker.

Sample code:

PipedInputStream pi = new PipedInputStream();
PipedOutputStream po = new PipedOutputStream(pi);
Writer writer = new OutputStreamWriter(po);
configuration.getTemplate("xx").process(rootMap, writer);

The issue is that sometimes it's freezing inside freemarker procsss method. No Error, no Exception, but it's not returning back from the process method.

If I convert the piped stream to a ByteArray stream, it works fine.

Am I using piped stream in correct way?

+2  A: 

No, piped streams are designed to pass data between two threads. There is only a small buffer between the ends of the pipe. If you write into the piped output stream, your thread will be blocked if the buffer is full until another thread will read from the corresponding piped input stream. This will not work with just one thread.

From the Javadoc:

Typically, data is read from a PipedInputStream object by one thread and data is written to the corresponding PipedOutputStream by some other thread.

So for small templates just use a StringWriter, for large ones you may use a FileWriter on a temp file created by File.createTempFile().

Arne Burmeister
@Arne: thanks for the replay.do you have any other solution for large templates? i can't write to temp file. (don't have Access)
mohammad shamsi
@mohammed: Do you really not have access? Or do you simply not know the right location to write to? There's usually a temporary directory that you've got permission to, if you can figure out where (hint: look at the `java.io.tmpdir` property).
Donal Fellows
@Donal: Application running on a Server (OSGI) and i am not sure that i can write to file in customer environment.
mohammad shamsi
@mohammed: Well, OSGi is currently outside my expertise (that may have changed by the end of the year) so I can't really advise from a position of knowledge, but I'd *really* suggest testing whether you can write in the directory given by that property. It's supposed to be a place you can write stuff (and which the OS will wipe from time to time).
Donal Fellows
A: 

As Arne writes, the amount of buffer space in a piped stream is fairly small. If you can't use a buffer that can hold all of the data (whether in memory or on disk) then one thing you could try is to see if you can run the template processing in another thread with a piped stream sending the results back to the main thread where you're doing this.

PipedInputStream pi = new PipedInputStream();
final Writer writer = new OutputStreamWriter(new PipedOutputStream(pi));
Thread worker = new Thread(new Runnable() {
    public void run() {
        configuration.getTemplate("xx").process(rootMap, writer);
    }
});
worker.start();

You might need to add final keywords to other variables to make this work in your real code. It depends on whether the variable configuration, the argument to getTemplate or the rootMap variable are local variables or instance (or class) variables.

(I could have subclassed Thread when specifying the thread's behavior of course, but I prefer to instantiate an interface – Runnable in this case – for such things.)

Donal Fellows