20 lutego 2013

Pierwszy projekt w Scali - obróbka XMLi przy migracji z WLI do IBM BPM

Chwała każdemu, komu udaje się dopiąć swego i wdrożyć nowy język w projekcie, aby produkt ciężkiej pracy umysłowej komuś ułatwił życie (niechby to był sam klient, albo koledzy programiści z zespołu).

A niechby to był taki malutki projekcik, jak ten mój, dzisiejszy do obrabiania XMLi. Nic nadzwyczajnego, ale czego oczekiwać od nowicjusza scalowego, który karierę w tym języku liczy w dniach (a nie tygodniach, czy miesiącach)?! Każdy przecież kiedyś był początkujący w rzeczach, w których teraz wiedzie prym. Ja właśnie zaczynam swoje pierwsze kroki w Scali i twory przypominają prawdziwe potwory, ale od czegoś zacząć należy!

Wierzę, że z pomocą Grześka, teamon'a oraz dmilith'a nauka Scali będzie tylko przyjemnością!

Pora na odsłonę mojego dzieła. Komentarze mile widziane.
package pl.japila.wli.transformations.control

import scala.xml.{ XML, Node, Elem }
import scala.xml.transform.{ RuleTransformer, RewriteRule }

object WLIControlMigrationMain {
  // FIXME: Remove it once the script reads input args or we find them a better place
  val pkg = "pl.japila.wli.transformations.control".replace(".", "/")
  
  def main(args: Array[String]) {
    // The file comes from the BPEL Exporter in WLI
    val processCtrlXml = XML.load(getClass.getResourceAsStream(s"/${pkg}/process_ctrl.wsdl"))
    val portType = (processCtrlXml \ "portType" \ "@name").text

    // The file is ours - the template for a JMS import
    val importXmlTemplate = XML.load(getClass.getResourceAsStream(s"/${pkg}/import-xml.template"))
    // The file name and the name of the import component must be alike
    val importComponentName = portType + "_MB_Publish_control"
    println(s"+++\n+++ Save the following file as ${importComponentName}.import:\n+++")
    println(importXmlTemplate.toString
      .replace("{importComponentName}", importComponentName)
      .replace("{portType}", portType))
    println(s"+++\n+++ Save the following file as process.component:\n+++")
    wireComponentWithImport(importComponentName)
  }

  def wireComponentWithImport(importComponentName: String) {
    val processComponentXML = XML.load(getClass.getResourceAsStream(s"/${pkg}/process.component"))
    val wire = XML.loadString(s"<wire target='${importComponentName}'/>")
    val wiredProcessComponentXML = new RuleTransformer(
                                     new AddChildrenTo("reference", wire))
                                       .transform(processComponentXML).head
    println(wiredProcessComponentXML)
  }

  // http://stackoverflow.com/questions/2199040/scala-xml-building-adding-children-to-existing-nodes
  def addChild(n: Node, newChild: Node) = n match {
    case Elem(prefix, label, attribs, scope, child @ _*) =>
      Elem(prefix, label, attribs, scope, child ++ newChild: _*)
    case _ => sys.error("Can only add children to elements!")
  }

  class AddChildrenTo(label: String, newChild: Node) extends RewriteRule {
    override def transform(n: Node) = n match {
      case Elem(_, `label`, _, _, _*) => addChild(n, newChild)
      case _ => n
    }
  }
}