Sunday 1 August 2010

Java: a fluent I/O API (2/4)

This is the second post about my experiments with a fluent I/O API. This post covers how to extend the API.

Doctoring streams

Let's look at some of the API's Doctor implementations. The code uses some static imports to keep things clean:

import static demo.fluentio.Closers.closer;
import static demo.fluentio.Doctors.DETECT_BOM;
import static demo.fluentio.Doctors.bom;
import static demo.fluentio.Drains.drain;

This code writes UTF-8 character data, prefixing the stream with a Unicode byte-order-mark:

  private void save(File output, String datathrows IOException {
    Closer closer = closer();
    try {
      Writer writer = IO.open(closer, output)
                        .utf8()
                        .doctor(bom())
                        .die();
      writer.write(data);
    finally {
      closer.close();
    }
  }

This code detects the encoding of a text file by inspecting the byte-order-mark:

  private String load(File inputthrows IOException {
    Closer closer = closer();
    try {
      InputStreamReader reader = IO.access(closer, input)
                                   .doctor(DETECT_BOM)
                                   .die();
      return drain(reader, new StringBuilder()).toString();
    finally {
      closer.close();
    }
  }

Extending the API

You can add support for other stream types by implementing your own Doctor implementations. This Doctor decorates a stream with a filter class (elided) that turns characters into upper case:

public class ShoutyDoctor implements
    Doctor<WriterDie<ShoutyWriter>, Die<Writer>> {
  public static ShoutyDoctor INSTANCE = new ShoutyDoctor();

  private ShoutyDoctor() {}

  @Override
  public WriterDie<ShoutyWriter> op(Die<Writer> fthrows IOException {
    Writer decorated = f.die();
    ShoutyWriter writer = new ShoutyWriter(decorated);
    return IO.writing(f.getCloser(), writer);
  }
}

This code prints out WOULD YOU LIKE TO PLAY A GAME?:

    PrintWriter shouter = IO.out(SHUT, System.out)
        .encode(defaultCharset())
        .operate(SHOUTY)
        .printer()
        .die();

    shouter.println("Would you like to play a game?");
    shouter.flush();

Doctoring streams

Adding decorators isn't the only thing you can do with a Doctor implementation. This code creates one to perform a byte copy operation:

  private static void copy(File src, File destthrows IOException {
    CoupledCloser closer = coupledCloser();
    try {
      Doctor<OutputStream, ?> drainBytesOp = access(closer.in(), src).drain();
      open(closer.out(), dest).doctor(drainBytesOp);
    finally {
      closer.close();
    }
  }

Related posts

Comments & criticism are welcome.

No comments:

Post a Comment

All comments are moderated