Winding down. Hacking PERL.
Vacations are for getting away from work and resting from the daily grind. Yet, almost everyone seems to need a week to unwind before getting to relax. My week of unwinding was productive.
During my last workweek, I was helping an employee configure Apache to simplify her life. While poking around on the development machine I noticed that the team was creating multiple WebSphere Application Server profiles. WebSphere Application Server (WAS) is IBMâ€™s J2EE platform and it supports the ability of running multiple instances of the runtime environment without installing the product several times. This can be a very powerful feature and in the case of my team, they were simply doing it for isolation. It allows each of them to manage an instance of WAS without worrying about affecting other peoples work. While this is a development machine, apparently one of the applications it ran is less â€œin the worksâ€ than the others. This presented a problem, when I wanted to front-end my employeeâ€™s application (the one I just configure Apache for) with the web server.
You see, in a typical WAS setup, there is a web server that receives requests from an end userâ€™s web browser. Web servers are extremely good at serving static content, executing CGI scripts and connecting to FastCGI applications. To hook into this layer, WAS loads a plugin that reads an XML configuration document to understand what it should do. This document, among other things, maps which URL paths should be passed on to WAS. For each WAS profile, a new plugin-cfg.xml file is generated. This makes sense, because each of these profiles is a different environment. The challenge is that the WAS plugin Apache loads can only read one XML file. So, what do you do when you want to map multiple WAS profiles to a single web server?
A few months ago, I remember the manager of the systems team we work with describing how this was a manual process and when he had more time, he would automate it. This led me to search and find a link for Lotus Connections documentation, “Mapping multiple WAS profiles to a single IBM HTTP Server,” that described the manual procedure. Using this as my guide, I updated the plugin-cfg.xml file manually and my employee was all set. It worked as expected and that was that. My last workday was the following day and yet I was compelled to automate this during my wind down week.
PERL is my programming language of choice when it comes to working with text and it fits perfectly for this task â€“ merging two plugin-cfg.xml files. There are four XML nodes to consider when merging these files: VirtualHostsGroup, ServerCluster, UriGroup and Route. The latter three are easy because they just need to be copied â€œas isâ€ into the merged XML document. VirtualHostsGroup however needs to be merged. Moreover, while the example from the Lotus Connections documentation shows a VirtualHostsGroup stanza named â€œdefault_hostâ€ and because this is XML, to do this responsibly we need to presume there could also be a VirtualHostGroup named something else. So, not only do we need to combing the children of all VirtualHostGroup nodes, we need to persist these nodes even if the named node in one XML file is not in the other.
With the help of XML::LibXML and XML::Tidy this task is simple enough. The following script takes three arguments, the file name of first XML document, the second XML document and the new XML document. It merges the second document into the first, inserting changes after the existing XML nodes. This approach ensures the file appears in a more logical human readable fashion. The formatting options available in LibXML disagreed with my aesthetics, so I added a dependency on XML::Tidy, which while cleaning up the document, makes it too neat. Oh well. The script could be used multiple times to merge several plugin-cfg.xml documents. For full disclosure, the IBM documentation for Lotus Connections mentions:
Do not complete this procedure if you are planning to add the multiple profiles to a node in a network deployment. In that case, you can define a Web server for the node and map only the node to the IBM HTTP Server.
I have not looked into what happens or what would need to happen to support multiple profiles in a network deployment. My last disclaimer is that I have tested this many times with a few edge cases. As with any software, it may have bugs, so test it on your documents before using this in a production environment. I will not be held liable for damage you create using this script. For that matter, if you plan to use it commercially, you should email me to discuss a license. Let me know if you find a bug or have suggestions.