anli
anli

Reputation: 377

Play framework: how to enumerate java.io.Writer?

An external library uses java.io.Writer interface for some kind of output, and at the moment I use StringWriter to buffer all output and then Ok(writer.toString). But I'd want to avoid buffering and to stream data supplied by Writer.

How to craft a Play Enumerator based on java.io.Writer?

Upvotes: 0

Views: 143

Answers (2)

anli
anli

Reputation: 377

With help of faissalb I have got this final working fragment (it is streaming of FreeMarker output, but can be used at any Writer-expected case, of course):

  class FltWriter(channel: Concurrent.Channel[Array[Byte]]) extends java.io.Writer {
    def write(cs: Array[Char], start: Int, len: Int): Unit = channel.push(new String(cs, start, len).getBytes("UTF-8"))
    def flush: Unit = channel.end
    def close: Unit = channel.eofAndEnd
  }

  def e(tpl: String, data: Map[String, Any], config: Configuration = cfg)(implicit ec: ExecutionContext) =
    Concurrent.unicast[Array[Byte]] { channel => config.getTemplate(tpl).process(data, new FltWriter(channel)) }

At the case (that is FreeMarker output) used flush is obligatory. You see, channel has moved into Writer constructor resulting in immutable code.

Upvotes: 0

faissalb
faissalb

Reputation: 1749

You can implement your own writer that uses a Concurrent.Channel to push data to an enumerator, let's talk code:

class MyWriter extends java.io.Writer{
var channel : Concurent.Channel
def write(x:Array[Char], s:Int, e:Int) = {
  channel.push(x)
}
def close() = {
  channel.end()
}
def flush() = {

}
}
// every time writer.write is used it will push data to the enumeratr
var writer = new YourWriter();
val enumerator:Enumerator[Array[Char]]  = Concurrent.unicast[Array[Char]](channel => {writer.channel = channel})

Upvotes: 1

Related Questions