Thursday, August 11, 2011

Scala + Maven + JavaFX 2.0? It's easy! (Part 1)

Preface

On May 26, 2011, Oracle released the beta SDK for JavaFX 2.0. The major difference between previous versions is that it provides Java APIs, allowing us to use JavaFX from normal Java applications. Ok, using JavaFX from Java is good, but what about Scala? Scala programs run on the same JVM as Java, so there should be no problems to use JavaFX from.

To prove that it is possible to use JavaFX from Scala, we will try to clone Oracle’s Getting Started with Java FX application. I think you already have Scala IDE or Scala Plugin for your favorite IDE? For this experiment I will use Eclipse Indigo + Scala IDE for Eclipse + Maven Integration (available in Eclipse Marketplace).

Monday, July 4, 2011

Merge .docx files in Java using docx4j

This code is used in one of the projects I was attached to. The first source file (stream) is used as master document, so, all styles defined in this one will be applied to subdocument (incl. headers and footers).
public class DocxService {
  private static final String CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";

  public InputStream mergeDocx(final List<InputStream> streams) throws Docx4JException, IOException {

    WordprocessingMLPackage target = null;
    final File generated = File.createTempFile("generated", ".docx");

    int chunkId = 0;
    Iterator<InputStream> it = streams.iterator();
    while (it.hasNext()) {
      InputStream is = it.next();
      if (is != null) {
        if (target == null) {
          // Copy first (master) document
          OutputStream os = new FileOutputStream(generated);
          os.write(IOUtils.toByteArray(is));
          os.close();

          target = WordprocessingMLPackage.load(generated);
        } else {
          // Attach the others (Alternative input parts)
          insertDocx(target.getMainDocumentPart(), IOUtils.toByteArray(is), chunkId++);
        }
      }
    }

    if (target != null) {
      target.save(generated);
      return new FileInputStream(generated);
    } else {
      return null;
    }
  }

  private static void insertDocx(MainDocumentPart main, byte[] bytes, int chunkId) {
    try {
      AlternativeFormatInputPart afiPart = new AlternativeFormatInputPart(new PartName("/part" + chunkId + ".docx"));
      afiPart.setContentType(new ContentType(CONTENT_TYPE));
      afiPart.setBinaryData(bytes);
      Relationship altChunkRel = main.addTargetPart(afiPart);

      CTAltChunk chunk = Context.getWmlObjectFactory().createCTAltChunk();
      chunk.setId(altChunkRel.getId());

      main.addObject(chunk);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}
Note: Generated file can be opened only in Microsoft Office 2007 or newer (Win/Mac). OpenOffice/LibreOffice render only the master document, ignorind attached ones.