0

XML Parsed/Serialized as [#document: null]

It’s a huge annoyance when you’re working with XML and after parsing the web service’s XML or deserializing the XML from BlazeDS, you see in your debugger that the output is [#document: null]. When I was still fresh out of the woods, I thought that [#document: null] is null, but as it turns out, it isn’t. The toString() method on the Document object is trying to communicate that the Document’s root element’s “node value” is not defined. Unfortunately, it chooses to represent that as [#document: null], which is just plain confusing.

If I’d read the Node documentation earlier, which states clearly that for the Document interface, the nodeName is “#document” and the nodeValue is null, it would have saved me many hours of frustration. If the XML API you’re working with returns you this output, you’d have to recurse through all the nodes and build the XML yourself. One way of avoiding this is to use JDOM:

import java.io.StringWriter;
import java.io.IOException;
import org.jdom.*;
import org.jdom.output.*;
import org.jdom.input.*;

public String buildXML(org.w3c.dom.Document xmlDoc) throws IOException
{
    xmlDoc.getDocumentElement().normalize();
    DOMBuilder domBuilder = new DOMBuilder();
    Document jdomDocument = domBuilder.build(xmlDoc);
    XMLOutputter xmlOutputter = new XMLOutputter(Format.getPrettyFormat());
    StringWriter stringWriter = new StringWriter();
    xmlOutputter.output(jdomDocument, stringWriter);
    String xmlString = stringWriter.toString();
    return xmlString;
}
0

Registering Mediators with Dynamic Views at Runtime in Robotlegs

Recently ran into a problem with Robotlegs due to my lack of experience with it. I was creating views dynamically at runtime and intended to automatically register their mediators via mediator.mapView in my context. However, the app just didn’t seem to hook the mediator to my view despite the mediator being created successfully.

After some googling, I found this piece of lifesaving advice – With Flex, a mediator’s onRegister() hook will only be called after creationComplete. So, the mediator gets created as soon as the view component lands on stage, but onRegister() only gets called when the view component dispatches creationComplete. With plain as3, onRegister() gets called sooner (immediately after the component is added to the stage).

Therefore, if your dynamic view needs to hit the database to populate some UI elements once it’s been added to the stage, you should register the event listeners in the onRegister() method of your listener and dispatch that event from your view (not your mediator) at the end of the onRegister() method. This approach is for those who want to go with an entirely async event driven design or the case where other views in your application need to respond to the creation of your new view, in which case the onRegister() method would dispatch an event to the context bus to alert all registered mediators.

0

Flex 4 Rich Text Editor, now with Spell Check

I’ve updated the Flex 4 RTE with US English spellchecking using the very useful Squiggly from Adobe Labs. Basically, it works like your typical MS Word spellcheck. Red squiggly lines will appear if it thinks you’ve mistyped something and you can right click to bring up a context menu to see your options.

One interesting bug that I ran into and wrestled with for 1 hour was that if you use a Spark Panel as your container, it swallows up your context menu and just gives you the plain ole Flash context menu. After some googling, I found out that it was already logged in Squiggly’s JIRA. As luck would have it, a very kind member provided a workaround. Make sure that you have mouseEnabled=true in your opening Panel tag as well as the listed creationComplete event handler:

<s:Panel
	title="SimpleTextEditor"
	horizontalCenter="0" verticalCenter="0"
	xmlns:fx="http://ns.adobe.com/mxml/2009"
	xmlns:s="library://ns.adobe.com/flex/spark"
	xmlns:mx="library://ns.adobe.com/flex/mx" height="300"
	mouseEnabled="true" creationComplete="creationCompleteHandler(event)"
	>

    protected function creationCompleteHandler(event:FlexEvent):void
    {
	    this.skin.mouseEnabled = true;
    }

Problem solved! As usual, you can play with it here and pull the repo from github.

2

Flex 4 Rich Text Editor via Text Layout Framework

Rolled my own RTE for Flex 4 recently due to the lackluster out-of-the-box RTE provided by Flex 4 using Adobe’s Text Layout Framework. It has all the standard stuff that you might expect from a typical RTE:

  • Font type selection
  • Font size selection
  • Multilanguage support
  • Justification
  • Font colours

which is already more than what Flex 4 gives us. I suppose one could use the RTE from Flex 3, but when you’re developing in Flex 4, it’s gonna be messy when you start to mix lots of Spark and Halo components together.

Besides, the main reason I had to roll my own RTE was because I wanted strikethrough, text search (incluging regex search) and undo functionality, which aren’t in Flex 3’s RTE anyway. The RTE can be found under the Projects menu header or one can jump directly to the example.

For those who are interested, feel free to clone the github repo and contribute.

4

Oracle XMLType in iBatis/MyBatis

I recently migrated 2 apps from the terribly ancient version of iBatis 2.3.4.726 to MyBatis 3.0.5 in order to comply with enterprise development standards and the experience was pretty smooth overall, with the help of this brief guide as well as the MyBatis documentation. The main pain came from Oracle’s XMLType. As XMLType is not a native JDBC type, a custom typehandler was created for iBatis. Due to the migration, some code tweaking needed to be done to get XMLType support running. For those who might be facing the same problems, I’ll run through some of the pitfalls.

First of all, the type handler for XMLType (found many months ago in the depths of the interweb after some googling) in ibatis 2.3.4.726 would have to change from this:

package project.callback;

import java.io.StringReader;
import java.sql.SQLException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.xml.sax.InputSource;

import oracle.jdbc.OraclePreparedStatement;
import oracle.jdbc.OracleResultSet;
import oracle.sql.OPAQUE;
import oracle.xdb.XMLType;
import oracle.xml.parser.v2.XMLParseException;

import com.ibatis.sqlmap.client.extensions.ParameterSetter;
import com.ibatis.sqlmap.client.extensions.ResultGetter;
import com.ibatis.sqlmap.client.extensions.TypeHandlerCallback;

/**
 * Custom type handler to map <code>oracle.xdb.XMLType</code> to
 * <code>org.w3c.dom.Document</code>. More specifically it allows us to map an
 * Oracle XMLType column onto a XML Document.
 */
public class XMLTypeHandlerCallback implements TypeHandlerCallback
{

	public Object getResult(ResultGetter getter) throws SQLException
	{
		if (getter.getResultSet() instanceof OracleResultSet)
		{
			OPAQUE opaqueValue = getOpaqueValue(getter);
			if (opaqueValue != null)
			{
				XMLType xmlResult = XMLType.createXML(opaqueValue);
				return xmlResult.getDocument();
			}
			else
			{
				return (Document) null;
			}
		}
		else
		{
			throw new UnsupportedOperationException("XMLType mapping only supported for Oracle RDBMS");
		}
	}

	public void setParameter(ParameterSetter setter, Object parameter) throws SQLException
	{
		if (setter.getPreparedStatement() instanceof OraclePreparedStatement)
		{
			OraclePreparedStatement ops = (OraclePreparedStatement) setter.getPreparedStatement();
			if (parameter == null)
			{
				ops.setNull(setter.getParameterIndex(), oracle.jdbc.OracleTypes.OPAQUE, "SYS.XMLTYPE");
			}
			else
			{
				XMLType xmlInput = XMLType.createXML(ops.getConnection(), (Document) parameter);
				// System.out.println(xmlInput.getStringVal());
				ops.setObject(setter.getParameterIndex(), xmlInput);
			}
		}
		else
		{
			throw new UnsupportedOperationException("XMLType mapping only supported for Oracle RDBMS");
		}
	}

	public Object valueOf(String s)
	{
		try
		{
			DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
			return db.parse(new InputSource(new StringReader(s)));
		}
		catch (Exception e)
		{
			if (e instanceof XMLParseException)
			{
				throw new IllegalArgumentException("Argument for valueOf() doesn't describe a XML Document");
			}
			else
			{
				throw new RuntimeException("Error creating XML document.  Cause: " + e);
			}
		}
	}

	private OPAQUE getOpaqueValue(ResultGetter getter) throws SQLException
	{
		OracleResultSet ors = (OracleResultSet) getter.getResultSet();
		OPAQUE op = null;
		if (getter.getColumnName() != null)
		{
			op = ors.getOPAQUE(getter.getColumnName());
		}
		else
		{
			op = ors.getOPAQUE(getter.getColumnIndex());
		}
		return op;
	}
}

to this version that we modified to be compatible with MyBatis 3.0.5:

package project.callback;

import java.io.StringReader;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;

import oracle.jdbc.OracleCallableStatement;
import oracle.jdbc.OraclePreparedStatement;
import oracle.jdbc.OracleResultSet;
import oracle.sql.OPAQUE;
import oracle.xdb.XMLType;
import oracle.xml.parser.v2.XMLParseException;

/**
 * Custom type handler to map <code>oracle.xdb.XMLType</code> to
 * <code>org.w3c.dom.Document</code>. More specifically it allows us to map an
 * Oracle XMLType column onto a XML Document.
 */
public class XMLTypeHandlerCallback implements TypeHandler
{
	final static Logger logger = LoggerFactory.getLogger(XMLTypeHandlerCallback.class);

	@Override
	public Object getResult(ResultSet resultSet, String columnName) throws SQLException
	{
		if (resultSet.unwrap(OracleResultSet.class) instanceof OracleResultSet)
		{
			OracleResultSet oracleResultSet = (OracleResultSet) resultSet.unwrap(OracleResultSet.class);
			OPAQUE opaqueValue = oracleResultSet.getOPAQUE(columnName);
			if (opaqueValue != null)
			{
				XMLType xmlResult = XMLType.createXML(opaqueValue);
				return xmlResult.getDocument();
			}
			else
			{
				return (Document) null;
			}
		}
		else
		{
			throw new UnsupportedOperationException("XMLType mapping only supported for Oracle RDBMS LOL");
		}
	}

	@Override
	public Object getResult(CallableStatement callableStatement, int columnIndex) throws SQLException
	{
		if (callableStatement.unwrap(OracleCallableStatement.class) instanceof OracleCallableStatement)
		{
			OracleCallableStatement oracleCallableStatement = (OracleCallableStatement) callableStatement.unwrap(OracleCallableStatement.class);
			OPAQUE opaqueValue = oracleCallableStatement.getOPAQUE(columnIndex);
			if (opaqueValue != null)
			{
				XMLType xmlResult = XMLType.createXML(opaqueValue);
				return xmlResult.getDocument();
			}
			else
			{
				return (Document) null;
			}
		}
		else
		{
			throw new UnsupportedOperationException("XMLType mapping only supported for Oracle RDBMS");
		}
	}

	@Override
	public void setParameter(PreparedStatement preparedStatement, int i, Object parameter, JdbcType jdbcType) throws SQLException
	{
		if (preparedStatement.unwrap(OraclePreparedStatement.class) instanceof OraclePreparedStatement)
		{
			OraclePreparedStatement oraclePreparedStatement = (OraclePreparedStatement) preparedStatement.unwrap(OraclePreparedStatement.class);
			if (parameter == null)
			{
				oraclePreparedStatement.setNull(i, oracle.jdbc.OracleTypes.OPAQUE, "SYS.XMLTYPE");
			}
			else
			{
				XMLType xmlInput = XMLType.createXML(oraclePreparedStatement.getConnection(), (Document) parameter);
				oraclePreparedStatement.setObject(i, xmlInput);
			}
		}
		else
		{
			throw new UnsupportedOperationException("XMLType mapping only supported for Oracle RDBMS");
		}

	}

	public Object valueOf(String s)
	{
		try
		{
			DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
			return db.parse(new InputSource(new StringReader(s)));
		}
		catch (Exception e)
		{
			if (e instanceof XMLParseException)
			{
				throw new IllegalArgumentException("Argument for valueOf() doesn't describe a XML Document");
			}
			else
			{
				throw new RuntimeException("Error creating XML document.  Cause: " + e);
			}
		}
	}
}

The main changes to take note of here are that we now

  • implement TypeHandler instead of TypeHandlerCallback
  • unwrap the SQL constucts instead of just doing an instanceof comparison, since these constucts are now wrapped in proxy objects

In addition, we can no longer use the old style of declaring custom typehandlers in the main sqlConfig.xml and resultMaps in sqlMap.xml. The relevant parts of the iBatis 2.3.4.726 xml look like this:

<!--sqlMapConfig.xml-->
<typeHandler javaType="org.w3c.dom.Document" jdbcType="XMLTYPE" callback="project.callback.XMLTypeHandlerCallback"/>

<!--sqlMap.xml-->
<resultMap id="PurchaseOrderMap" class="project.dto.PurchaseOrder" >
	<result property="orderInfo" jdbcType="XMLTYPE"/>
</resultMap>

For MyBatis 3.0.5, we’ll have to declare them as such:

<!--sqlMapConfig.xml-->
<typeHandlers>
	<typeHandler javaType="org.w3c.dom.Document" handler="project.callback.XMLTypeHandlerCallback"/>
</typeHandlers>

<!--sqlMap.xml-->
<resultMap id="PurchaseOrderMap" type="project.dto.PurchaseOrder" >
	<result property="orderInfo" javaType="org.w3c.dom.Document" typeHandler="project.callback.XMLTypeHandlerCallback"/>
</resultMap>

As it turns out, we no longer have to specify jdbcType. Instead, we specify the custom typehandler we wish to use to handle our esoteric datatype. With that out of the way, let’s get back to the joy of programming with MyBatis and XMLType!

ps: For those who are interested in finding more about XMLType, apart from the typical white papers and slides that you can find on OTN, another good resource for XMLType info is Marco Gralike’s blog.

0

Java Pitfalls, Groovy to the rescue

Came across this interesting Java gotcha recently, which has surely caused some really infuriating bugs for some hapless programmer out there. I thought it would be good to document it here and also one alternative workaround. Consider the following:

import java.util.ArrayList;

public class TestCode
{
	public static void main(String[] args)
	{
		ArrayList<String> list = new ArrayList<String>();
		list.add("one");
		list.add("two");
		list.add("three");
		list.remove(0);
		System.out.println("Result1: " + (2 == list.size()));
		// Result1: true
	}
}

The result, of course, is expected. However, consider the following version, where we change ArrayList to Collection:

import java.util.Collection;

public class TestCode
{
	public static void main(String[] args)
	{
		Collection<String> list = new ArrayList<String>();
		list.add("one");
		list.add("two");
		list.add("three");
		list.remove(0);
		System.out.println("Result2: " + (2 == list.size()));
		// Result2: false
	}
}

The result is false because the list size is still 3! We can thank autoboxing for this. The problem lies with the fact that the Collection interface has a remove method, but this method removes the item matching the content, not the item in that index order, which is what the remove method of ArrayList does. In this case, Java autoboxes the integer 2 into an Integer object, looks in the list to see if there is an element with the content of 2, fails to find one, and doesn’t remove anything from the list.

To me, this is a definite code smell as one of the guidelines of clean code is that a method named foobar() in one class should have the exact same functionality as a foobar() in another class. For example, if you have a method called checkForUser(userName) in an authentication module that well, checks if an user exists, a checkForUser(userName) in another authentication module, apart from checking if the user exists, should NOT add the user if the check is negative! Code smells like this lead to many hours of frustrating debugging, especially in big teams on big projects.

However, all is not lost. As mentioned in the title, Groovy will help to save your day. Try out the Groovy code below:

ArrayList<String> list = new ArrayList<String>()
list.add("one")
list.add("two")
list.add("three")
list.remove(0)
println 2 == list.size()
// true

Collection<String> list_ = new ArrayList<String>()
list_.add("one")
list_.add("two")
list_.add("three")
list_.remove(0)
println 2 == list_.size()
// true

You’ll see that Groovy is smart enough to keep things consistent as the results are both true! Of course, on the flip side, if you’re a seasoned Java veteran for whom quirks like this are ingrained in your soul, you might find the Groovy interpretation of remove unnatural. Personally for me though, the Groovy interpretation is much more natural and intuitive.

0

Singletons – A Code Smell

I’ve been using static methods and singletons blindly for so long that I’ve never paid much thought to how smelly they were until I was enlightened by The Productive Programmer recently. Static methods, as we all know, have one wonderful use: as a black-box, standalone, stateless method. The use of static methods of the Math class in Java illustrates good use. When you call the Math.sqrt() method, you don’t worry that a subsequent call might return the cube root instead of the square root because some state within the sqrt() method changed. Static methods work well when they are completely stateless. You get into trouble when you start mixing staticness and state.

The evil code smell emitted by the singleton design pattern arises from the combination of “static” and “state”. The goal of a singleton is to create a class that can be instantiated only once and all subsequent attempts to create an instance of the class return the original instance. In most code I’ve seen, as well as ALL the code I’ve written, the singleton is typically implemented like this:

public class ConfigSingleton
{
    private static ConfigSingleton myInstance;
    private Point _initialPosition;

    public Point getInitialPosition()
	{
        return _initialPosition;
    }

    private ConfigSingleton()
	{
        Dimension screenSize =
                Toolkit.getDefaultToolkit().getScreenSize();
        _initialPosition = new Point();
        _initialPosition.x = (int) screenSize.getWidth() / 2;
        _initialPosition.y = (int) screenSize.getHeight() / 2;
    }

    public static ConfigSingleton getInstance()
	{
        if (myInstance == null)
            myInstance = new ConfigSingleton();
        return myInstance;
    }
}

In the code above, the getInstance() method checks to see if one already exists, creates the sole instance if needed, then returns the reference to it. Note that this method isn’t thread safe, but this post isn’t about thread safety and it just adds more complexity. The thing that’s so evil about the singleton is the embedded state, which makes it untestable. Unit testing manipulates state, but there is no way to manipulate the state of this singleton object. Because construction is atomic in Java, there is no way you can test this class with any value of initialPosition rather than the constructed value derived from the current screen size. A singleton is the object-oriented version of a global variable, and everyone knows that global variables are bad. Of course, sad to say, this is how I’ve been writing singletons all my life.

Ultimately, what makes singleton so smelly is the fact that you have a single class that has two distinct responsibilities: policing the instances of itself and providing configuration information. Any time you have a single class with multiple unrelated responsibilities, you have a code smell. But it’s always useful to have only a single configuration object, so how can you achieve that without using a singleton? The recommendation from the Productive Programmer is that you can use a plain object plus a factory, delegating the individual responsibilities to each where the factory is responsible for policing the instance and the POJO deals only with configuration information and behavior.

Here is the updated configuration object as a POJO:

public class Configuration
{
    private Point _initialPosition;

    private Configuration(Dimension screenSize)
	{
        _initialPosition = new Point();
        _initialPosition.x = (int) screenSize.getWidth() / 2;
        _initialPosition.y = (int) screenSize.getHeight() / 2;
    }
    public int getInitialX()
	{
        return _initialPosition.x;
    }

    public int getInitialY()
	{
        return _initialPosition.y;
    }
}

This class is trivial to test. Both the unit test and factory will use reflection to create the class. In Java, private access is little more than documentation indicating suggested usage. In modern languages, you can always bypass it with reflection if the need arises. This represents a good case where you don’t expect anyone to instantiate one of these classes; therefore, the constructor is private. The following code shows the unit tests for this class, including the instantiation via reflection and accessing the private field via reflection to test the class’s behavior with different values:

public class TestConfiguration
{
      Configuration c;

      @Before
	  public void setUp()
	  {
          try
		  {
              Constructor cxtor[] =
                      Configuration.class.getDeclaredConstructors();
              cxtor[0].setAccessible(true);
              c = (Configuration) cxtor[0].newInstance(
                      Toolkit.getDefaultToolkit().getScreenSize());
          }
		  catch (Throwable e)
		  {
              fail();
          }
      }

      @Test
      public void initial_position_set_correctly_upon_instantiation()
	  {
          Configuration specialConfig = null;
          Dimension screenSize = null;
          try
		  {
              Constructor cxtor[] =
                      Configuration.class.getDeclaredConstructors();
              cxtor[0].setAccessible(true);
              screenSize = new Dimension(26, 26);
              specialConfig = (Configuration) cxtor[0].newInstance(screenSize);
          }
		  catch (Throwable e)
		  {
              fail();
          }
          Point expected = new Point();
          expected.x = (int) screenSize.getWidth() / 2;
          expected.y = (int) screenSize.getHeight() / 2;
          assertEquals(expected.x, specialConfig.getInitialX());
          assertEquals(expected.y, specialConfig.getInitialY());
      }

      @Test
      public void initial_postion_can_be_changed_after_instantiation()
	  {
          Field f = null;
          try
		  {
              f = Configuration.class.getDeclaredField("_initialPosition");
              f.setAccessible(true);
              f.set(c, new Point(10, 10));
          }
		  catch (Throwable t)
		  {
              fail();
          }
          Assert.assertEquals(10, c.getInitialX());
      }
}

The setUp() method creates the Configuration object via reflection and calls initialize() to create a valid object for most of the tests. You can access the private field _initialPosition using reflection to see what would happen in your configuration class if the initial position is something other than the default. Making the Configuration class a plain object ensures that it is easy to test and doesn’t compromise any of the functionality it had before. The factory responsible for creating configuration is also simple and testable; the code for ConfigurationFactory appears here:

public class ConfigurationFactory
{
    private static Configuration myConfig;

    public static Configuration getConfiguration()
	{
        if (myConfig == null)
		{
            try
			{
                Constructor cxtor[] =
                    Configuration.class.getDeclaredConstructors();
                cxtor[0].setAccessible(true);
                myConfig = (Configuration) cxtor[0].newInstance(
                        Toolkit.getDefaultToolkit().getScreenSize());
            }
			catch (Throwable e)
			{
                throw new RuntimeException("can't construct Configuration");
            }
        }
        return myConfig;
    }
}

Not surprisingly, this code looks just like the creation code from the original singleton. The important difference is that this code does only one thing: police the instances of the
Configuration class. The ConfigurationFactory is also very testable, as shown here:

public class TestConfigurationFactory
{
      @Test
      public void creation_creates_a_single_instance()
	  {
          Configuration config1 = ConfigurationFactory.getConfiguration();
          assertNotNull(config1);
          Configuration config2 = ConfigurationFactory.getConfiguration();
          assertNotNull(config2);
          assertSame(config1, config2);
      }
  }

Not only does it just feel right, it looks so much cleaner doesn’t it? I’m definitely going to refactor my singletons the next time I step into the office!

0

Game of Thrones Word Cloud Fun

Given the recent interest in Song of Fire and Ice recently due to the HBO premiere of Game of Thrones, I did up the word cloud below for GoT using Wordle
Wordle: Game of Thrones

This is pretty interesting since a SoFaI newbie can draw the following conclusions from looking at the word cloud:

  • Lords and Sers abound in the book
  • Jon, Catelyn, Tyrion, Ned, Dany and Arya all play a pretty major role in the book
  • Pycelle? Not so much
  • etc…

For those who are interested in doing this to their favorite pdfs, here’s the groovy code that I cobbled together to extract the text from pdf:

package extract

import com.itextpdf.text.pdf.PdfReader
import com.itextpdf.text.pdf.parser.PdfTextExtractor

class Book
{
	def path
	def start
	def end
	def outputFileName

    // start - page in the .pdf you want to start extracting from. No point extracting from preface and content pages
    // end - last page to stop extracting. Not interested in the family descriptions, etc
	Book(path, start, end, outputFileName)
	{
		this.path = path
		this.start = start
		this.end = end
		this.outputFileName = outputFileName
	}
}

books = []
books.add(new Book("C:\\book1.pdf", 3, 553, "book1.txt"))
books.add(new Book("C:\\book2.pdf", 3, 596, "book2.txt"))

for (eachBook in books)
{
	reader = new PdfReader(eachBook.path)
	wordList = [];

	for (i in eachBook.start..eachBook.end)
	{
		page = PdfTextExtractor.getTextFromPage(reader, i)
		lines = page.split()
		for (eachWord in lines)
		{
            // Because I only want to capture entities and not ALL the text,
            // the regex below is a naive method to capture only words that start with
            // an uppercase letter, e.g ,Ned\" and have at least 2 characters as there's
            // a good chance that it's an entity. This can be made more sophisticated with time.
			capitalisedWordRegex= /.*?([A-Z][a-zA-Z]+).*/
			matcher = (eachWord =~ capitalisedWordRegex)
			if (matcher.matches())
				wordList.add(matcher[0][1])
		}
	}

	outputFile = new File(eachBook.outputFileName)
	for (eachWord in wordList)
		outputFile.withWriterAppend{ file -> file << eachWord + "\n"}
	println "Finished $eachBook.path"
}

Once you have the output file, you can create your word cloud using by going to Wordle, or you can download Wordle and generate a picture which you can save and use. Here’s some of the clouds I generated.

0

Building XML strings in Java

I had to build relatively simple XML strings from user input recently in a project and was trying to come up with a beautiful, elegant solution to do it. Naturally, manual string concatenation was out. It’s messy, brittle, and basically a nightmare to maintain. My next alternative was XMLBeans but I rejected as it was too heavyweight. I didn’t need to register a schema and it was simply too inefficient and a huge overkill to use XMLBeans to generate a straightforward XML string due to the amount of boilerplate required.

Another consideration was that I wanted to build the string in the style of fluent interfaces, such that one could simply tell if the string was well formed simply by eyeballing it. I thought of using VTD-XML, which was the XML parser being used in the project, but I couldn’t find any XML building capabilities, only parsing ones. I then settled on JDom as I’ve used it before as well as a new kid on the block, java-xmlbuilder (uses JAXP internally to build the DOM). With that, let’s see some code!

JDom version:

Element orderXml= new Element("ORDER").addContent(new Element
							("ORDER_DETAILS").addContent(new Element
									("ORDER_ID").setText(
										"123"))).addContent(new Element
							("SHOP_DETAILS").addContent(new Element
									("SHOP_TYPE").setText
										("ONLINE")).addContent(new Element
									("SHOP_COUNTRY").setText
										("SG")));

XMLOutputter xmlOutputter = new XMLOutputter(Format.getPrettyFormat());
StringWriter stringWriter = new StringWriter();
xmlOutputter.output(new Document(orderXml), stringWriter);
System.out.println(stringWriter.toString());

// JDom output
<?xml version="1.0" encoding="UTF-8"?>
<ORDER>
  <ORDER_DETAILS>
    <ORDER_ID>123</ORDER_ID>
  </ORDER_DETAILS>
  <SHOP_DETAILS>
    <SHOP_TYPE>ONLINE</SHOP_TYPE>
    <SHOP_COUNTRY>SG</SHOP_COUNTRY>
  </SHOP_DETAILS>
</ORDER>

java-xmlbuilder version:

XMLBuilder xmlBuilder =
			XMLBuilder.create("ORDER")
								.e("ORDER_DETAILS")
									.e("ORDER_ID")
										.t("123")
									.up()
								.up()
								.e("SHOP_DETAILS")
									.e("SHOP_TYPE")
										.t("ONLINE")
									.up()
									.e("SHOP_COUNTRY")
										.t("SG");

Properties outputProperties = new Properties();
outputProperties.put(javax.xml.transform.OutputKeys.INDENT, "yes");
outputProperties.put("{http://xml.apache.org/xslt}indent-amount", "2");
System.out.println(xmlBuilder.asString(outputProperties));

// java-xmlbuilder output
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<ORDER>
  <ORDER_DETAILS>
    <ORDER_ID>123</ORDER_ID>
  </ORDER_DETAILS>
  <SHOP_DETAILS>
    <SHOP_TYPE>ONLINE</SHOP_TYPE>
    <SHOP_COUNTRY>SG</SHOP_COUNTRY>
  </SHOP_DETAILS>
</ORDER>

Needless to say, I decided to use java-xmlbuilder as I found it more readable and also, it’s more easier to write code in the style of fluent interfaces with it. With JDom, I had to really pay attention to the indentation and bracketing as the correct visual position of the elements do not necessarily mean that your XML is well-formed. Get the order of your method calls and your closing brackets mixed up and even though it looks right, the resulting string will be malformed.

For java-xmlbuilder, coding in the style of fluent interfaces comes naturally due to the API and the brackets are simple to match up. The really cool thing about this is that once you have finished adding items to a new element, you can call the up() method to retrieve the XMLBuilder node that represents the parent of the current node. If you balance every call to element() with a call to up(), you can write code that closely resembles the structure of the XML document you are creating.

Verdict: java-xmlbuilder

1 2 3