<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Jason R Briggs &#187; jython</title>
	<atom:link href="http://www.briggs.net.nz/log/tag/jython/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.briggs.net.nz/log</link>
	<description>Techie stuff from the perspective of a Kiwi abroad</description>
	<lastBuildDate>Mon, 28 Jun 2010 06:45:23 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>jython and jndi</title>
		<link>http://www.briggs.net.nz/log/2007/02/28/jython-and-jndi/</link>
		<comments>http://www.briggs.net.nz/log/2007/02/28/jython-and-jndi/#comments</comments>
		<pubDate>Wed, 28 Feb 2007 19:35:51 +0000</pubDate>
		<dc:creator>jrbriggs</dc:creator>
				<category><![CDATA[technical]]></category>
		<category><![CDATA[jython]]></category>

		<guid isPermaLink="false">http://www.briggs.net.nz/log/2007/02/28/jython-and-jndi/</guid>
		<description><![CDATA[Recently been playing with OSS application servers for the first time in ages. So far, Glassfish, JBoss and Geronimo. Geronimo is a mess. To put it politely. After looking at what&#8217;s missing from their web console, a brief experiment with trying to add a jar to the repository, and a few other false starts, the [...]]]></description>
			<content:encoded><![CDATA[<p>Recently been playing with OSS application servers for the first time in ages.  So far, Glassfish, JBoss and Geronimo.</p>
<p>Geronimo is a mess.</p>
<p>To put it politely.</p>
<p>After looking at what&#8217;s missing from their web console, a brief experiment with trying to add a jar to the repository, and a few other false starts, the law of diminishing returns kicked in, and I decided to give up before wasting too much time.</p>
<p>Glassfish seems quite polished by comparison (which is a surprise considering I was never that enthused by iPlanet&#8230; but then, the last time I looked at <em>that</em> was about a million years ago).</p>
<p>JBoss hasn&#8217;t changed a lot since I last looked at it.  Still has the hideous applet-driven console app &#8212; but then configuring JBoss has always been a case of direct editing of config files (which is part of its attraction really).</p>
<p>Odd difference between the two.  When accessing an InitialContext from an external app, in Glassfish you can get access to a configured data source, but in JBoss it doesn&#8217;t seem to be accessible.  I&#8217;m a bit hazy now about how JBoss&#8217; JNDI works, so I can&#8217;t recall if this is expected behaviour or not.</p>
<p>In any case, for testing purposes, these Jython excerpts are useful:</p>
<p>1.  To access a Glassfish context, set the classpath to:</p>
<pre>
<code>
glassfish/lib/appserv-rt.jar:glassfish/lib/javaee.jar:glassfish/lib/appserv-admin.jar:glassfish/lib/webservices-rt.jar:glassfish/lib/install/applications/jmsra/imqjmsra.jar
</code>
</pre>
<p>(plus whatever jars you need for the resources you&#8217;re accessing), then invoke the following in Jython:</p>
<pre>
<code>
from java.util import *
from javax.naming import *
p = Properties()
p.put("java.naming.factory.initial", "com.sun.enterprise.naming.SerialInitContextFactory")
p.put("java.naming.factory.url.pkgs", "com.sun.enterprise.naming")
p.put("java.naming.factory.state", "com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl")
ic = InitialContext(p)
</code>
</pre>
<p>2.  To access a JBoss context, set the classpath to:</p>
<pre>
<code>
jboss/client/jnp-client.jar:jboss/server/all/lib/jnpserver.jar:jboss/client/logkit.jar:jboss/lib/jboss-common.jar
</code>
</pre>
<p>&#8230;then invoke the following in Jython:</p>
<pre>
<code>
from java.util import *
from javax.naming import *
p = Properties()
p.put("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory")
p.put("java.naming.factory.url.pkgs", "org.jboss.naming:org.jnp.interfaces")
p.put("java.naming.provider.url", "jnp://localhost:1099")
ic = InitialContext(p)
</code>
</pre>
<p>Hope that&#8217;s useful for somebody.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.briggs.net.nz/log/2007/02/28/jython-and-jndi/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>vaguely useful hack</title>
		<link>http://www.briggs.net.nz/log/2006/06/23/vaguely-useful-hack/</link>
		<comments>http://www.briggs.net.nz/log/2006/06/23/vaguely-useful-hack/#comments</comments>
		<pubDate>Fri, 23 Jun 2006 19:33:50 +0000</pubDate>
		<dc:creator>jrbriggs</dc:creator>
				<category><![CDATA[development]]></category>
		<category><![CDATA[technical]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[jython]]></category>

		<guid isPermaLink="false">http://www.briggs.net.nz/log/2006/06/23/vaguely-useful-hack/</guid>
		<description><![CDATA[This is one of the more useful hacks I&#8217;ve thrown together lately. It&#8217;s a simple console application for accessing a hibernate domain (i.e. you can execute queries such as &#8220;from Blah where x = 1&#8243;), so you don&#8217;t have to deploy your application to test minor changes to hql statements. It is, by no means, [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.briggs.net.nz/sup/2006/06/23/vaguely-useful-hack/hibernate-console.py">This</a> is one of the more useful hacks I&#8217;ve thrown together lately. It&#8217;s a simple console application for accessing a hibernate domain (i.e. you can execute queries such as &#8220;from Blah where x = 1&#8243;), so you don&#8217;t have to deploy your application to test minor changes to hql statements.</p>
<p>It is, by no means, an endorsement of hibernate; rather a reflection on the fact that I can&#8217;t find any tools to access the domain which don&#8217;t require the use of Eclipse (&lt;sarcasm-alert&gt;because, of course, <em><strong>everyone</strong></em> uses eclipse&lt;/sarcasm-alert&gt;).</p>
<p>In any case, the script needs to be executed with a classpath referencing the hibernate jars, jython jars, your domain classes, and anything else hibernate &#038; jython might need to access &#8212; I run it from within ant, but it could quite easily be executed from a shellscript.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.briggs.net.nz/log/2006/06/23/vaguely-useful-hack/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>pydev experiences&#8230;</title>
		<link>http://www.briggs.net.nz/log/2006/01/30/pydev-experiences/</link>
		<comments>http://www.briggs.net.nz/log/2006/01/30/pydev-experiences/#comments</comments>
		<pubDate>Mon, 30 Jan 2006 15:38:00 +0000</pubDate>
		<dc:creator>jrbriggs</dc:creator>
				<category><![CDATA[technical]]></category>
		<category><![CDATA[jython]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://localhost/log/2006/01/30/pydev-experiences/</guid>
		<description><![CDATA[A quick install of the Eclipse-SDK proved more painful than expected, purely because my system-vm was set to Java1.5, which is problematic (at the moment) on gentoo. java-config (the tool used to set the vm for the system, or for a user) appears to be semi-borked on my machine (or I don&#8217;t know how to [...]]]></description>
			<content:encoded><![CDATA[<p>A quick install of the Eclipse-SDK proved more painful than expected, purely because my system-vm was set to Java1.5, which is problematic (at the moment) on gentoo.  java-config (the tool used to set the vm for the system, or for a user) appears to be semi-borked on my machine (or I don&#8217;t know how to use it properly), because it kept switching back to 1.5 despite the fact that I set it explicity to 1.4.  So after removing 1.5, and recompiling (re-emerging) a mass of dependencies, eclipse and the pydev plugin finally installed.</p>
<p>First impressions, after not having looked a the Eclipse 3 platform for a while:</p>
<p>1.  NetBeans panelling is -way- more slick than Eclipse.  Eclipse seems clunky by comparison &#8212; perhaps there is a way to set a &#8220;FastView&#8221; panel to open on mouse-over like NetBeans, but it wasn&#8217;t immediately obvious&#8230;?</p>
<p>2.  Also because the panelling isn&#8217;t as good, the Eclipse screen layout doesn&#8217;t work as well unless you have a large screen, I think.  I&#8217;m running a small widescreen on a laptop (1280 x 800), and the editor interior seems vertically challenged unless you minimise the bottom panel &#8212; which wouldn&#8217;t be an issue, if it wasn&#8217;t for the fact that the UI is designed by touchpad bigots (a majority of window managers are able to put the close, minimise and maximise buttons in a group on a window title-bar, so why does Eclipse have to be different?), so it seems as if more touchpad use is required to perform the same action on Eclipse when compared with NetBeans.</p>
<p>3.  The method to add new file filters isn&#8217;t obvious to me either</p>
<p>4.  Fonts are a lot (in large flashing letters on a billboard somewhere) nicer on Eclipse than on NetBeans.  NetBeans is hard to look at after Eclipse.  JEdit is generally ghastly as well from the font perspective &#8212; both suffering from Java&#8217;s traditionally wonderful font management (that&#8217;s sarcasm in case it&#8217;s not apparent).</p>
<p>5.  It seems that the blame for the chunky behaviour of WSAD/RAD (+Linux) should fall squarely on the heads of the IBM teams in charge of <strike>corrupting</strike> (I mean) enhancing Eclipse, because alone, it&#8217;s a lot more responsive, and memory usage is considerably better than NetBeans.  Doing nothing, NetBeans sits at about 17-19% memory usage.  Eclipse is currently (doing nothing) sitting on 9.7%.</p>
<p>6.  I still don&#8217;t like the way that most (all?) IDEs force you to work to their project formats &#8212; i.e. create a web project, create a simple java project, etc.  A simple text editor with plugins you can twist around, to your own liking, seems much more attractive &#8212; but I&#8217;m probably in the minority.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.briggs.net.nz/log/2006/01/30/pydev-experiences/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>TDD, Jython &amp; REST (Part 3)</title>
		<link>http://www.briggs.net.nz/log/2005/10/02/tdd-jython-rest-part-3/</link>
		<comments>http://www.briggs.net.nz/log/2005/10/02/tdd-jython-rest-part-3/#comments</comments>
		<pubDate>Sun, 02 Oct 2005 15:27:00 +0000</pubDate>
		<dc:creator>jrbriggs</dc:creator>
				<category><![CDATA[technical]]></category>
		<category><![CDATA[jython]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[REST]]></category>
		<category><![CDATA[TDD]]></category>

		<guid isPermaLink="false">http://localhost/log/2005/10/02/tdd-jython-rest-part-3/</guid>
		<description><![CDATA[With the addition of xml validation and value checking, the testing scripts actually become somewhat useful: > PUT http://localhost:8080/ws/user '' 'username=testuser1&#38;email_address=testuser1@test.com' > GET http://localhost:8080/ws/user/testuser1 < assert status 200 < assert header Content-Type text/xml < assert xmlschema ../web/user.xsd < assert xmlbody /user/username=testuser1 < assert xmlbody /user/email_address=testuser1@test.com > DELETE http://localhost:8080/ws/user/testuser1 Depak Vohra&#8217;s article at ONJava, shows how [...]]]></description>
			<content:encoded><![CDATA[<p>With the addition of xml validation and value checking, the testing scripts actually become somewhat useful:</p>
<pre>
<code>
> PUT http://localhost:8080/ws/user ''
    'username=testuser1&amp;email_address=testuser1@test.com'
> GET http://localhost:8080/ws/user/testuser1
< assert status 200
< assert header Content-Type text/xml
< assert xmlschema ../web/user.xsd
< assert xmlbody /user/username=testuser1
< assert xmlbody /user/email_address=testuser1@test.com
> DELETE http://localhost:8080/ws/user/testuser1
</code>
</pre>
<p>Depak Vohra&#8217;s <a href="http://www.onjava.com/pub/a/onjava/2004/09/15/schema-validation.html">article</a> at ONJava, shows how to perform schema validation using xerces/jaxp.  Adapting his code to jython is straightforward, by adding the following imports to the test script from <a href="http://jasonrbriggs.blogspot.com/2005/09/tdd-jython-rest-part-2.html">part 2</a>:</p>
<pre>
<code>
from java.<span class="pyname">io</span> <span class="pykeyword">import</span> StringReader
from java.<span class="pyname">lang</span> <span class="pykeyword">import</span> System
from javax.<span class="pyname">xml</span>.<span class="pyname">parsers</span> <span class="pykeyword">import</span> DocumentBuilderFactory
from javax.<span class="pyname">xml</span>.<span class="pyname">parsers</span> <span class="pykeyword">import</span> DocumentBuilder
from org.<span class="pyname">xml</span>.<span class="pyname">sax</span>.<span class="pyname">helpers</span> <span class="pykeyword">import</span> DefaultHandler
from org.<span class="pyname">xml</span>.<span class="pyname">sax</span> <span class="pykeyword">import</span> InputSource

System.<span class="pyname">setProperty</span>(<span class="pystring">'javax.xml.parsers.DocumentBuilderFactory'</span>,
        <span class="pystring">'org.apache.xerces.jaxp.DocumentBuilderFactoryImpl'</span>)
</code>
</pre>
<p>Depak&#8217;s Validator becomes:</p>
<pre>
<code>
<span class="pykeyword">class</span> <span class="pyname">Validator</span>(DefaultHandler):
    <span class="pykeyword">def</span> <span class="pyname">__init__</span>(self):
        self.<span class="pyname">validationError</span> = <span class="pynumber">0</span>
        self.<span class="pyname">saxParseException</span> = None

    <span class="pykeyword">def</span> <span class="pyname">error</span>(self, exception):
        self.<span class="pyname">validationError</span> = <span class="pynumber">1</span>
        self.<span class="pyname">saxParseException</span> = exception

    <span class="pykeyword">def</span> <span class="pyname">fatalError</span>(self, exception):
        self.<span class="pyname">validationError</span> = <span class="pynumber">1</span>
        self.<span class="pyname">saxParseException</span> = exception      

    <span class="pykeyword">def</span> <span class="pyname">warning</span>(self, exception):
        pass
</code>
</pre>
<p>Finally, a new assertion method is added to the Test class:</p>
<pre>
<code>
    <span class="pycomment">#</span>
    <span class="pycomment"># assert that an xml document validates against an xml schema</span>
    <span class="pycomment">#</span>
    <span class="pykeyword">def</span> <span class="pyname">assert_xmlschema</span>(self, linearr, req, res):
        xml = res.<span class="pyname">getContent</span>()

        factory = DocumentBuilderFactory.<span class="pyname">newInstance</span>()
        factory.<span class="pyname">setNamespaceAware</span>(<span class="pynumber">1</span>)
        factory.<span class="pyname">setValidating</span>(<span class="pynumber">1</span>)
        factory.<span class="pyname">setAttribute</span>(<span class="pystring">'http://java.sun.com/xml/jaxp/properties/schemaLanguage'</span>,
                <span class="pystring">'http://www.w3.org/2001/XMLSchema'</span>)
        errhandler = Validator()
        factory.<span class="pyname">setAttribute</span>(<span class="pystring">'http://java.sun.com/xml/jaxp/properties/schemaSource'</span>,
            linearr[<span class="pynumber">0</span>])
        builder = factory.<span class="pyname">newDocumentBuilder</span>()
        builder.<span class="pyname">setErrorHandler</span>(errhandler)

        dom = builder.<span class="pyname">parse</span>(InputSource(StringReader(xml)))

        <span class="pykeyword">if</span> errhandler.<span class="pyname">validationError</span> == <span class="pynumber">1</span>:
            errmsg = <span class="pystring">'%s, %s'</span> % (<span class="pyfunction">str</span>(errhandler.<span class="pyname">validationError</span>),
                    errhandler.<span class="pyname">saxParseException</span>.<span class="pyname">getMessage</span>())
        <span class="pykeyword">else</span>:
            errmsg = <span class="pystring">''</span>

        assert errhandler.<span class="pyname">validationError</span> != <span class="pynumber">1</span>, errmsg
</code>
</pre>
<p>Value checking is accomplished with the following method:</p>
<pre>
<code>
    <span class="pycomment">#</span>
    <span class="pycomment"># assert that a particular xml element contains a particular value</span>
    <span class="pycomment">#</span>
    <span class="pykeyword">def</span> <span class="pyname">assert_xmlbody</span>(self, linearr, req, res):
        xml = res.<span class="pyname">getContent</span>()
        <span class="pykeyword">if</span> not self.<span class="pyname">xml</span> <span class="pykeyword">or</span> self.<span class="pyname">xml</span> != xml:
            factory = DocumentBuilderFactory.<span class="pyname">newInstance</span>()
            factory.<span class="pyname">setNamespaceAware</span>(<span class="pynumber">1</span>)
            builder = factory.<span class="pyname">newDocumentBuilder</span>()
            self.<span class="pyname">dom</span> = builder.<span class="pyname">parse</span>(InputSource(StringReader(xml)))
            self.<span class="pyname">xml</span> = xml

        <span class="pycomment"># get rid of the starting '/'</span>
        <span class="pycomment"># (could leave this out in the test, but it looks better in to me)</span>
        <span class="pykeyword">if</span> linearr[<span class="pynumber">0</span>].<span class="pyname">startswith</span>(<span class="pystring">'/'</span>):
            linearr[<span class="pynumber">0</span>] = linearr[<span class="pynumber">0</span>][<span class="pynumber">1</span>:]

        <span class="pycomment"># split into xml element list and a value based on the first '=' position</span>
        equalspos = linearr[<span class="pynumber">0</span>].<span class="pyname">find</span>(<span class="pystring">'='</span>)
        tmp = linearr[<span class="pynumber">0</span>][<span class="pynumber">0</span>:equalspos]
        value = linearr[<span class="pynumber">0</span>][equalspos+1:]
        elements = tmp.<span class="pyname">split</span>(<span class="pystring">'/'</span>)

        <span class="pycomment"># loop through the elements in the list and retrieve each named node</span>
        node = self.<span class="pyname">dom</span>
        <span class="pykeyword">for</span> x <span class="pykeyword">in</span> xrange(<span class="pynumber">0</span>, <span class="pyfunction">len</span>(elements)):
            nl = node.<span class="pyname">getElementsByTagName</span>(elements[x])
            <span class="pykeyword">if</span> not nl:
                raise AssertionError, <span class="pystring">'sub element "%s" is missing'</span> % elements[x]
            <span class="pykeyword">else</span>:
                node = nl.<span class="pyname">item</span>(<span class="pynumber">0</span>)
            <span class="pykeyword">if</span> x == <span class="pyfunction">len</span>(elements)-1:
                eval = node.<span class="pyname">getFirstChild</span>().<span class="pyname">getNodeValue</span>()
                assert eval == value, <span class="pystring">'element %s (value "%s") does not match expected %s'</span>
                            % (elements[x], eval, value)
                return
        raise AssertionError, <span class="pystring">'missing element %s'</span> % tmp
</code>
</pre>
<p>Which takes an assertion line such as &#8220;assert xmlbody /user/username=testuser1&#8243; and looks up elements in the dom, where &#8220;user&#8221; is the root node, and &#8220;username&#8221; is a child node of user.  At the moment this is very basic value checking which won&#8217;t work well for more complicated documents &#8212; but I&#8217;m trying to avoid complication as much as possible anyway, so it&#8217;s difficult to justify (to myself at least) going to greater lengths to make something more flexible.  The main enhancement I&#8217;m looking to make initially is the ability to specify the nth child of a node.  For example, something like the string &#8220;/list/user[2]/username&#8221; (in case it&#8217;s not painfully obvious, the second &#8220;user&#8221; element in &#8220;list&#8221;).</p>
<p>But for the moment, this will hopefully get me going.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.briggs.net.nz/log/2005/10/02/tdd-jython-rest-part-3/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>TDD, Jython &amp; REST (Part 2)</title>
		<link>http://www.briggs.net.nz/log/2005/09/28/tdd-jython-rest-part-2/</link>
		<comments>http://www.briggs.net.nz/log/2005/09/28/tdd-jython-rest-part-2/#comments</comments>
		<pubDate>Wed, 28 Sep 2005 17:28:00 +0000</pubDate>
		<dc:creator>jrbriggs</dc:creator>
				<category><![CDATA[technical]]></category>
		<category><![CDATA[jython]]></category>
		<category><![CDATA[REST]]></category>
		<category><![CDATA[TDD]]></category>

		<guid isPermaLink="false">http://localhost/log/2005/09/28/tdd-jython-rest-part-2/</guid>
		<description><![CDATA[In part one of this rumination, I discussed test-driven-development of a REST-style application written using Jython. An example of a test method would be something like: def test_getvaliduser(): req = MockHttpServletRequest('GET', 'user', 'http://localhost:8080/ws/user/testuser1', '', '') req.setContentType('text/html') res = MockHttpServletResponse() user.doGet(req, res) assert res.getStatus() == 200, 'incorrect status %s (%s)' % (res.getStatus(), res.getReason()) assert res.getContentType().startswith('text/html'), 'expected [...]]]></description>
			<content:encoded><![CDATA[<p>In part <a href="http://jasonrbriggs.blogspot.com/2005/09/tdd-jython-rest.html">one</a> of this rumination, I discussed test-driven-development of a REST-style application written using Jython. An example of a test method would be something like:</p>
<pre>
<code>
<span class="pykeyword">def</span> <span class="pyname">test_getvaliduser</span>():
    req = MockHttpServletRequest(<span class="pystring">'GET'</span>, <span class="pystring">'user'</span>, <span class="pystring">'http://localhost:8080/ws/user/testuser1'</span>, <span class="pystring">''</span>, <span class="pystring">''</span>)
    req.<span class="pyname">setContentType</span>(<span class="pystring">'text/html'</span>)

    res = MockHttpServletResponse()

    user.<span class="pyname">doGet</span>(req, res)

    assert res.<span class="pyname">getStatus</span>() == <span class="pynumber">200</span>, <span class="pystring">'incorrect status %s (%s)' % (res.getStatus(), res.getReason())</span>
    assert res.<span class="pyname">getContentType</span>().<span class="pyname">startswith</span>(<span class="pystring">'text/html'</span>), <span class="pystring">'expected text/html, got %s'</span> % res.<span class="pyname">getContentType</span>()
</code>
</pre>
<p>The main problem I have with this idea, is the amount of coding (read: effort) required for each test method, and therefore the amount of duplicated effort testing each resource (servlet). Testing other components in this manner, or testing non-standard functionality, is another matter, of course.</p>
<p>I&#8217;ve come up with what I believe is a more workable solution.  Reducing the previous example to something like the following:</p>
<pre>
<code>
== Get Valid User
> GET http://localhost:8080/ws/user/testuser1
< assert status 200
</code>
</pre>
<p>Which is a serious reduction in the amount of typing required for a test, particularly when you add the setup functions (missing from the 'old' test example):</p>
<pre>
<code>
== Get Valid User
> PUT http://localhost:8080/ws/user '' &#92;
    'username=testuser1&amp;email_address=testuser1@test.com&amp;level=1&amp;password=password'
> GET http://localhost:8080/ws/user/testuser1
< assert status 200
< assert header Content-Type text/xml
> DELETE http://localhost:8080/ws/user/testuser1
</code>
</pre>
<p>Hopefully the script is relatively straightforward to understand: '==' signifies a new test, '&gt;' is an http call, and 'here</a>.</p>
<p>The next step is to add handlers for checking the content in the response (particularly xml), both in form and content.</p>
<p>(If anyone is interested in a working example, let me know and I'll endeavour to post something useable)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.briggs.net.nz/log/2005/09/28/tdd-jython-rest-part-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>TDD, Jython &amp; REST (Part 1)</title>
		<link>http://www.briggs.net.nz/log/2005/09/16/tdd-jython-rest-part-1/</link>
		<comments>http://www.briggs.net.nz/log/2005/09/16/tdd-jython-rest-part-1/#comments</comments>
		<pubDate>Fri, 16 Sep 2005 18:34:00 +0000</pubDate>
		<dc:creator>jrbriggs</dc:creator>
				<category><![CDATA[technical]]></category>
		<category><![CDATA[jython]]></category>
		<category><![CDATA[REST]]></category>
		<category><![CDATA[TDD]]></category>

		<guid isPermaLink="false">http://localhost/log/2005/09/16/tdd-jython-rest-part-1/</guid>
		<description><![CDATA[I&#8217;ve been working on a personal project for a few months now (begun while living in Thailand for a few months), combining a number of different technologies I currently find interesting. I&#8217;ve chosen Jython as the programming language in recognition of how powerful I&#8217;ve found developing in Python &#8212; the reasons for not going completely [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been working on a personal project for a few months now (begun while living in Thailand for a few months), combining a number of different technologies I currently find interesting. I&#8217;ve chosen Jython as the programming language in recognition of how powerful I&#8217;ve found developing in Python &#8212; the reasons for not going completely down the Python route (much as I would like to be using Py 2.4 modules) are mainly because of library issues. In particular I haven&#8217;t found a templating library as good as <a href="http://jakarta.apache.org/velocity">Velocity</a> in the Pythonic world.  Of course there is  <a href="http://www.cheetahtemplate.org/">Cheetah</a>, but while it is as close to Velocity as it&#8217;s possible to be without &#8216;sleeping in the same bed&#8217;, there is still something about Cheetah that rubs me the wrong way. I suspect it&#8217;s simply because, as a long time Velocity user, I have become so accustomed to the techniques we use with that library, that slight changes/quirks in the other become larger issues, completely out of proportion to their actual magnitude.</p>
<p><a href="http://en.wikipedia.org/wiki/Representational_State_Transfer">REST</a> is less a technology than a way of thinking which I&#8217;m endeavouring to apply to both personal and professional projects. How successful that application is remains to be seen, but thinking about web services in terms of a resource with a simple set of verbs, has certainly resulted in a re-think about how one approaches component development. It&#8217;s difficult to justify a full J2EE deployment (EJBs and so on) when your operations are reduced to a basic four (GET, POST, PUT, DELETE) and the business logic fits comfortably within the framework provided by a servlet (in my case a Jython-Servlet).</p>
<p>Finally <a href="http://en.wikipedia.org/wiki/Test_driven_development">TDD</a> (which technically should&#8217;ve been mentioned first, considering where it falls in the development cycle), comes from the understanding that developing a project, which I hope to eventually turn into something commercially viable, requires more than just hacking together a bunch of parts in the hope that my frankenstein will live when electricity is applied to its extremities. I have to also consider the future of this system &#8212; have confidence in both my design and in any changes/refactoring I might make to it after it has a community of users.</p>
<p>TDD is at the crux of the code sample below.  This is just the beginnings of a testing system for my rest+jython servlets.</p>
<p>It may make more sense, to some, to reuse what&#8217;s already available (JUnit for example, or the unit-testing modules already included in Python/Jython), but this is as much a learning exercise, as serious development, since I haven&#8217;t yet had to opportunity to apply TDD in any professional projects.</p>
<p><span id="more-12"></span></p>
<pre>
<code>
<span class="pycomment">#! /usr/bin/env ../bin/jython</span>

<span class="pykeyword">import</span> base64
<span class="pykeyword">import</span> sys

<span class="pykeyword">def</span> <span class="pyname">authbasic</span>(username, password):
    return <span class="pystring">'Basic %s'</span> % base64.<span class="pyname">encodestring</span>(<span class="pystring">'%s:%s'</span> % (username, password))

global successtests
successtests = <span class="pynumber">0</span>
global failedtests
failedtests = <span class="pynumber">0</span>
global errortests
errortests = <span class="pynumber">0</span>

<span class="pykeyword">def</span> <span class="pyname">contains</span>(srclist, matchlist):
   <span class="pykeyword">for</span> i <span class="pykeyword">in</span> matchlist:
       <span class="pykeyword">if</span> i not <span class="pykeyword">in</span> srclist:
           return false
   return true

<span class="pycomment">#</span>
<span class="pycomment"># given a module name and a list of tests, run each test in the module</span>
<span class="pycomment">#</span>
<span class="pykeyword">def</span> <span class="pyname">runTests</span>(mod, testnames=None):
   global successtests
   global failedtests
   global errortests

   exec <span class="pystring">'import %s as testmod'</span> % mod
   <span class="pykeyword">if</span> hasattr(testmod, <span class="pystring">'setup'</span>):
       getattr(testmod, <span class="pystring">'setup'</span>)()

   <span class="pykeyword">for</span> name <span class="pykeyword">in</span> dir(testmod):
       <span class="pykeyword">if</span> name.<span class="pyname">startswith</span>(<span class="pystring">'test_'</span>):

           <span class="pykeyword">if</span> testnames:
               chkname = name[<span class="pynumber">5</span>:]
               <span class="pykeyword">if</span> chkname not <span class="pykeyword">in</span> testnames:
                   <span class="pykeyword">continue</span>

           try:
               try:
                   <span class="pycomment"># get the method from the module object</span>
                   testmethod = getattr(testmod, name)

                   <span class="pycomment"># run the test, and if successful increment our counter</span>
                   testmethod()
                   successtests = successtests + <span class="pynumber">1</span>
               except AssertionError, ae:
                   <span class="pycomment"># handle assertion failures</span>
                   failedtests = failedtests + <span class="pynumber">1</span>
                   print '[%s] failed because of "%s"' % (name, <span class="pyfunction">str</span>(ae))
           except Exception, e:
               <span class="pycomment"># handle errors that fall outside of the test boundaries</span>
               errortests = errortests + <span class="pynumber">1</span>
               print '[%s] failed because of "%s"' % (name, <span class="pyfunction">str</span>(e))
               (type, value, traceback) = sys.<span class="pyname">exc_info</span>()
               print traceback.<span class="pyname">dumpStack</span>()

   print <span class="pystring">'''%s tests succeeded</span>
%s tests failed assertions
%s tests failed because of errors''' % (successtests, failedtests, errortests)

<span class="pykeyword">if</span> __name__ == <span class="pystring">'__main__'</span>:
   <span class="pykeyword">if</span> <span class="pyfunction">len</span>(sys.<span class="pyname">argv</span>) == <span class="pynumber">2</span>:
       runTests(sys.<span class="pyname">argv</span>[<span class="pynumber">1</span>])
   <span class="pykeyword">elif</span> <span class="pyfunction">len</span>(sys.<span class="pyname">argv</span>) == <span class="pynumber">3</span>:
       runTests(sys.<span class="pyname">argv</span>[<span class="pynumber">1</span>], sys.<span class="pyname">argv</span>[<span class="pynumber">2</span>].<span class="pyname">split</span>(','))
</code>
</pre>
<p>NB:  I&#8217;ve hacked out some of the functionality required to set up that particular test (such as creating and deleting the user record), but you get the idea.</p>
<p>A sample scripting testing a valid user of a user management web service would look like this:</p>
<pre>
<code>
from wstesting <span class="pykeyword">import</span> MockServletContext, MockServletConfig, MockHttpServletRequest, MockHttpServletResponse

<span class="pykeyword">import</span> miscutils
<span class="pykeyword">import</span> test

<span class="pykeyword">import</span> props

global user
user = None

<span class="pykeyword">def</span> <span class="pyname">setup</span>():
   <span class="pycomment"># change the database connect string to use the test database</span>
   props.<span class="pyname">db_connect_string</span> = <span class="pystring">'jdbc:postgresql:testdb'</span></span>

   <span class="pycomment"># dynamically load the module</span>
   usermod = miscutils.<span class="pyname">loadmod</span>('.<span class="pyname">.</span>/web',<span class="pystring">'user.py'</span>)

   <span class="pycomment"># create a servlet context for testing with</span>
   ctx = MockServletContext.<span class="pyname">getInstance</span>().<span class="pyname">setRootPath</span>('.<span class="pyname">.</span>/web')

   <span class="pycomment"># load the servlet and then initialise with the config object</span>
   global user
   user = usermod.<span class="pyname">user</span>()
   user.<span class="pyname">init</span>(MockServletConfig(<span class="pystring">'user'</span>))

<span class="pykeyword">def</span> <span class="pyname">test_getvaliduser</span>():
   req = MockHttpServletRequest(<span class="pystring">'GET'</span>, <span class="pystring">'user'</span>, <span class="pystring">'http://localhost:8080/ws/user/testuser1'</span>, <span class="pystring">''</span>, <span class="pystring">''</span>)
   req.<span class="pyname">setContentType</span>(<span class="pystring">'text/html'</span>)

   res = MockHttpServletResponse()

   user.<span class="pyname">doGet</span>(req, res)

   assert res.<span class="pyname">getStatus</span>() == <span class="pynumber">200</span>, <span class="pystring">'incorrect status %s (%s)' % (res.getStatus(), res.getReason())</span>
   assert res.<span class="pyname">getContentType</span>().<span class="pyname">startswith</span>(<span class="pystring">'text/html'</span>), <span class="pystring">'expected text/html, got %s'</span> % res.<span class="pyname">getContentType</span>()
</code>
</pre>
<p>So that&#8217;s the basic, lots of typing approach to TDD for my REST app. Next step is to completely scrap that structure, and do it the right way (i.e. a method that doesn&#8217;t involve writing the similar code over and over again for each service). More on that later&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.briggs.net.nz/log/2005/09/16/tdd-jython-rest-part-1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>pseudofork</title>
		<link>http://www.briggs.net.nz/log/2005/08/03/pseudofork/</link>
		<comments>http://www.briggs.net.nz/log/2005/08/03/pseudofork/#comments</comments>
		<pubDate>Wed, 03 Aug 2005 15:04:00 +0000</pubDate>
		<dc:creator>jrbriggs</dc:creator>
				<category><![CDATA[technical]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[jython]]></category>

		<guid isPermaLink="false">http://localhost/log/2005/08/03/pseudofork/</guid>
		<description><![CDATA[fork() is an excessively useful feature in the python os module, particularly when you&#8217;re daemonizing something, or otherwise creating a single subprocess where it doesn&#8217;t make sense to use processes with a lower atomic weight, such as threads. Its lack in Jython (and in Python on Windows for that matter&#8230; not that I care) is [...]]]></description>
			<content:encoded><![CDATA[<p>fork() is an excessively useful feature in the python os module, particularly when you&#8217;re <a href="http://en.wikipedia.org/wiki/Daemon_(computer_software)">daemonizing</a> something, or otherwise creating a single subprocess where it doesn&#8217;t make sense to use processes with a lower atomic weight, such as threads. Its lack in Jython (and in Python on Windows for that matter&#8230; not that I care) is something I&#8217;ve had cause to lament recently (if only because forking is considerably more elegant than the coding required for threads). So I&#8217;ve created my own pseudo fork functionality for jython &#8212; little more than a hack wrapped around some threading code. It is certainly a demonstration in how -not- to write python code. There is a good percentage of the script I would like to do better (I would particularly like to somehow get a handle on the AST and copy out the currently executing code, rather than reading in a script and trying to exec from the forked line), but for the moment, it works for my limited test cases, so I present it here as a severely limited work-in-progress.</p>
<p>NB. pseudofork will not work if called from the console, it must be called from a script.</p>
<p>The source for pseudofork can be found below:</p>
<p><span id="more-9"></span></p>
<pre>
<code>
<span class="pykeyword">import</span> copy
<span class="pykeyword">import</span> os
<span class="pykeyword">import</span> re
<span class="pykeyword">import</span> string
<span class="pykeyword">import</span> sys
<span class="pykeyword">import</span> threading

from java.<span class="pyname">io</span> <span class="pykeyword">import</span> InputStream
from java.<span class="pyname">lang</span> <span class="pykeyword">import</span> Thread
from org.<span class="pyname">python</span>.<span class="pyname">util</span> <span class="pykeyword">import</span> PythonInterpreter
from org.<span class="pyname">python</span>.<span class="pyname">core</span> <span class="pykeyword">import</span> Py

pat = re.<span class="pyname">compile</span>(r'(s*).<span class="pyname">*'</span>)
repl_re = re.<span class="pyname">compile</span>(r'myos.<span class="pyname">(</span>forkpseudofork)()')

<span class="pycomment"># not a real pid (obviously)</span>
global pid
pid = <span class="pynumber">1000</span>

lock = threading.<span class="pyname">Lock</span>()

<span class="pycomment">#</span>
<span class="pycomment"># a pretend fork routine, which basically creates a new thread,</span>
<span class="pycomment"># starts up a python interpreter in that thread, reads the source</span>
<span class="pycomment"># code from the calling script and then attempts to continue execution</span>
<span class="pycomment"># from that point in the new thread.</span>
<span class="pycomment">#</span>
<span class="pykeyword">def</span> <span class="pyname">pseudofork</span>():
   frame = sys.<span class="pyname">_getframe</span>(<span class="pynumber">1</span>)
   <span class="pykeyword">if</span> hasattr(threading.<span class="pyname">currentThread</span>(), <span class="pystring">'__forkedcode__'</span>):
       s = threading.<span class="pyname">currentThread</span>().<span class="pyname">__forkedcode__</span>
   else:
       f = file(frame.<span class="pyname">f_code</span>.<span class="pyname">co_filename</span>)
       s = f.<span class="pyname">read</span>()

   split = s.<span class="pyname">split</span>(<span class="pystring">'n'</span>)
   callingline = split[frame.<span class="pyname">getline</span>()-1]

   mat = pat.<span class="pyname">match</span>(callingline)
   <span class="pykeyword">if</span> mat:
       indent = <span class="pyfunction">len</span>(mat.<span class="pyname">group</span>(<span class="pynumber">1</span>))
   else:
       indent = <span class="pynumber">0</span>
   sindent = (<span class="pystring">'%'</span> + <span class="pyfunction">str</span>(indent) + <span class="pystring">'s'</span>) % ' '

   lock.<span class="pyname">acquire</span>()
   global pid
   pid = pid + <span class="pynumber">1</span>
   lock.<span class="pyname">release</span>()

   lines = [ repl_re.<span class="pyname">sub</span>(<span class="pyfunction">str</span>(pid), callingline) ]
   <span class="pykeyword">for</span> x <span class="pykeyword">in</span> xrange(frame.<span class="pyname">getline</span>(), <span class="pyfunction">len</span>(split)):
       <span class="pykeyword">if</span> indent == <span class="pynumber">0</span> <span class="pykeyword">or</span> split[x] == <span class="pystring">''</span> <span class="pykeyword">or</span> split[x].<span class="pyname">startswith</span>(sindent):
           lines.<span class="pyname">append</span>(split[x][indent:])
       else:
           break
   code = <span class="pystring">'n'</span>.<span class="pyname">join</span>(lines)

   localvars = copy.<span class="pyname">copy</span>(frame.<span class="pyname">f_locals</span>)
   <span class="pykeyword">if</span> localvars.<span class="pyname">has_key</span>(<span class="pystring">'frame'</span>):
       del localvars[<span class="pystring">'frame'</span>]

   <span class="pykeyword">for</span> key <span class="pykeyword">in</span> frame.<span class="pyname">f_globals</span>.<span class="pyname">keys</span>():
       <span class="pykeyword">if</span> not localvars.<span class="pyname">has_key</span>(key):
           localvars[key] = frame.<span class="pyname">f_globals</span>[key]

   thr = thread(code, localvars)
   thr.<span class="pyname">start</span>()

   return <span class="pynumber">0</span>

<span class="pycomment">#</span>
<span class="pycomment"># we'll pretend to be a fork as well</span>
<span class="pycomment">#</span>
fork = pseudofork

<span class="pycomment">#</span>
<span class="pycomment"># thin wrapper over a java.lang.Thread to pseudo-fork some code</span>
<span class="pycomment"># (why didn't I use jython 'threading'?  I forget)</span>
<span class="pycomment">#</span>
<span class="pykeyword">class</span> <span class="pyname">thread</span>(Thread):
   <span class="pykeyword">def</span> <span class="pyname">__init__</span>(self, execstr, localvars):
       Thread.<span class="pyname">__init__</span>(self)
       self.<span class="pyname">execstr</span> = execstr
       self.<span class="pyname">localvars</span> = localvars

   <span class="pykeyword">def</span> <span class="pyname">run</span>(self):
       interp = PythonInterpreter(self.<span class="pyname">localvars</span>, Py.<span class="pyname">getSystemState</span>())
       threading.<span class="pyname">currentThread</span>().<span class="pyname">__forkedcode__</span> = self.<span class="pyname">execstr</span>
       interp.<span class="pyname">exec</span>(self.<span class="pyname">execstr</span>)
</code>
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.briggs.net.nz/log/2005/08/03/pseudofork/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
