Red Squirrel Reflections
Dave Hoover explores the psychology of software development

Dave Hoover
dave.hoover@gmail.com

Categories
All [Atom]
Craftsmanship [Atom]
Dynamic [Atom]
Intersection [Atom]
Learning [Atom]
Links [Atom]
Polyglot [Atom]
Projects [Atom]
XP [Atom]
Old Blog

Obtivian Blogs

Andy Maleh
Colin Harris
Fred Polgardy
Jim Breen
Kevin Taylor
Todd Webb
Turner King
Tyler Jennings

Archives

March 2009 (1)
January 2009 (1)
December 2008 (1)
October 2008 (3)
September 2008 (1)
June 2008 (4)
April 2008 (3)
March 2008 (1)
February 2008 (1)
August 2007 (1)
July 2007 (1)
June 2007 (1)
May 2007 (4)
April 2007 (3)
March 2007 (5)
February 2007 (6)
January 2007 (6)
December 2006 (10)
November 2006 (5)
October 2006 (8)
September 2006 (8)
August 2006 (5)
July 2006 (12)
June 2006 (7)
May 2006 (5)
April 2006 (5)
March 2006 (4)
February 2006 (2)
January 2006 (5)
December 2005 (5)
November 2005 (3)
October 2005 (3)
September 2005 (6)
August 2005 (4)
July 2005 (7)
June 2005 (14)
May 2005 (6)
April 2005 (8)
March 2005 (9)
February 2005 (11)
January 2005 (16)
Old Archives

 

Mon, 07 Feb 2005

Quotes Manager Project -- Day 13

An ongoing pet project blog...

As I explore my solution, I see that subsequent calls to add a new quote actually append the entire document to the previous document. That's obviously not what I want.

Ah, solved the problem I found yesterday. The hasText method in PersonPanel was messed up. Just an annoying firstName.getText() != "" vs. !"".equals(firstName.getText()) issue. I didn't think I would need to write a test for something that trivial. Stupid mistake.

Now for the second problem... Before the XML output is generated from the Document, I need to somehow empty the file. Not sure how to do that off the top of my head with only an OutputStream. Exploring...grrr, can't do it. I really don't want XmlQuoteListener to have to use files becauses that makes the testing harder.

I'm feeling stuck, so I'll write a failing test...

    public void testShouldWriteDocumentToFileWhenUpdatedMultipleTimes() throws Exception {
        Document document = parseStub();

        ByteArrayOutputStream output = new ByteArrayOutputStream();
        QuoteListener listener = new XmlQuoteListener(document, output);

        assertEquals("", output.toString());

        listener.update();
        listener.update();

        String expectedOutput = documentToText(document);
        assertEquals(expectedOutput, output.toString());
    }
OK, this test fails and identifies the problem. If I can get it to pass, I'll be in good shape. Maybe I'll have more clarity on the way home...we're pulling into Chicago...

How about a factory to provide OutputStreams? That way we could get a new one with every call to update...

    public void testShouldWriteDocumentToFileWhenUpdatedMultipleTimes() throws Exception {
        Document document = parseStub();

        ByteArrayOutputStream output = new ByteArrayOutputStream();

        Mock factory = mock(OutputFactory.class);
        OutputStream ignored = new ByteArrayOutputStream();
        factory.expects(atLeastOnce()).method("newOutput")
               .will(onConsecutiveCalls(returnValue(ignored), returnValue(output)));

        QuoteListener listener = new XmlQuoteListener(document, (OutputFactory) factory.proxy());

        assertEquals("", output.toString());

        listener.update();
        listener.update();

        String expectedOutput = documentToText(document);
        assertEquals(expectedOutput, output.toString());
    }
This won't compile and I'll take a couple biggish steps to make it pass...
public class XmlQuoteListener implements QuoteListener {
    private final Document document;
    private final OutputFactory factory;

    public XmlQuoteListener(Document document, OutputFactory factory) {
        this.document = document;
        this.factory = factory;
    }

    public void update() {
        try {
            Transformer transformer = TransformerFactory.newInstance().newTransformer();
            Source source = new DOMSource(document);
            Result result = new StreamResult(factory.newOutput());
            transformer.transform(source, result);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
OK, I've pushed the responsibility down. I have yet another anonoymous class (this time an OutputFactory) in my main method...
    public static void main(String[] args) throws Exception {
        JFrame frame = new JFrame(TITLE);

        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();

        final String xmlFile = "play.xml";
        Document document = builder.parse(xmlFile);

        QuoteListener listener = new XmlQuoteListener(document, new OutputFactory() {
            public OutputStream newOutput() throws IOException {
                return new FileOutputStream(xmlFile);
            }
        });

        QuoteManager manager = new XmlQuoteManager(document);
        manager.addListener(listener);

        QuoteManagerPanel quoterManager = new QuoteManagerPanel(manager);
        frame.getContentPane().add(quoterManager);

        frame.pack();
        frame.setVisible(true);
    }
I'll run the app and to see if that fixes my problem. I have an uneasy feeling about creating a new OutputStream every time... But hey, it worked like a charm! Time for a check in.

So let's look back at the initial goals and see where we are...

  • I want to change the quotes page to be sorted by quoter author. DONE. There should be a list of all the quoters at the top. NOT DONE. Their names should link down to their quotes on the page below. NOT DONE.
  • I want to use a simple Swing application to manage the quotes. FIRST RELEASE: ADD QUOTE
  • The Swing app will store the quotes in XML. DONE. The app will have the ability to transform this XML into HTML via XSLT. NOT DONE.
Cool, this is good. If you don't mind, I'm going knock out the rest of this stuff without writing it up. I need to be moving onto other commute-time activities ASAP. Like reading and finding more quotes...and using my new software.

If anyone is interested, I'll post the final source code when I'm finished.

[/projects/quotes] permanent link


powered by blosxom