<?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>Blog</title>
	<atom:link href="http://www.scarba05.co.uk/blog/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.scarba05.co.uk/blog</link>
	<description></description>
	<lastBuildDate>Wed, 18 Apr 2012 15:21:06 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>How to test sending a http HEAD request to Plone / Zope</title>
		<link>http://www.scarba05.co.uk/blog/2012/01/how-to-test-sending-a-http-head-request-to-plone-zope/</link>
		<comments>http://www.scarba05.co.uk/blog/2012/01/how-to-test-sending-a-http-head-request-to-plone-zope/#comments</comments>
		<pubDate>Tue, 24 Jan 2012 16:24:11 +0000</pubDate>
		<dc:creator>Anthony</dc:creator>
				<category><![CDATA[Plone]]></category>

		<guid isPermaLink="false">http://www.scarba05.co.uk/blog/?p=220</guid>
		<description><![CDATA[Today I was trying to fix a bug whereby the image on one of my custom portlets was returning a 500 HTTP response to a HEAD request.  It took my quite some time to figure out how to write a test for this so I thought I&#8217;d write a quick post to share what I [...]]]></description>
			<content:encoded><![CDATA[<p>Today I was trying to fix a bug whereby the image on one of my custom portlets was returning a 500 HTTP response to a HEAD request.  It took my quite some time to figure out how to write a test for this so I thought I&#8217;d write a quick post to share what I learnt.</p>
<p>Once you realise the <code>zope.testbrowser.browser.Browser.open</code> accepts a <code>urllib2.Request</code> object as a parameter as well as a string then it all falls into place.  I could only get this working from a doc test:</p>
<pre><code>
     &gt;&gt;&gt; from Products.Five.testbrowser import Browser
     &gt;&gt;&gt; browser = Browser()
     &gt;&gt;&gt; from urllib2 import Request
     &gt;&gt;&gt; class HeadRequest(Request):
     ...     def get_method(self):
     ...         return "HEAD"
     &gt;&gt;&gt; head_request = HeadRequest(url_of_object_to_test)
     &gt;&gt;&gt; browser.open(head_request)
     &gt;&gt;&gt; browser.headers['content-type']
     'image/jpeg'</code></pre>
<p>Getting my image to support HEAD requests took a bit of work but that&#8217;s a different post…</p>
]]></content:encoded>
			<wfw:commentRss>http://www.scarba05.co.uk/blog/2012/01/how-to-test-sending-a-http-head-request-to-plone-zope/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Adobe Fireworks £60 more expensive to download from the UK than the U.S. and Canada</title>
		<link>http://www.scarba05.co.uk/blog/2011/11/adobe-fireworks-60-more-expensive-to-download-from-the-uk-than-the-u-s-and-canada/</link>
		<comments>http://www.scarba05.co.uk/blog/2011/11/adobe-fireworks-60-more-expensive-to-download-from-the-uk-than-the-u-s-and-canada/#comments</comments>
		<pubDate>Fri, 11 Nov 2011 17:35:14 +0000</pubDate>
		<dc:creator>Anthony</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.scarba05.co.uk/blog/?p=211</guid>
		<description><![CDATA[I&#8217;d like to buy Adobe Fireworks via a download from the adobe.com website.  Why does this cost me £100 more (or £60 if you add VAT) than if I&#8217;m in the U.S. and download it from the very same website.  How annoying!  Here&#8217;s a record of my chat with Victor from Adobe. Please hold as [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;d like to buy Adobe Fireworks via a download from the adobe.com website.  Why does this cost me £100 more (or £60 if you add VAT) than if I&#8217;m in the U.S. and download it from the very same website.  How annoying!  Here&#8217;s a record of my chat with Victor from Adobe.</p>
<p style="padding-left: 30px;"><strong>Please hold as we route your chat to an Adobe Representative.</strong></p>
<p style="padding-left: 30px;">Welcome to Adobe.com! My name is Victor. May I assist you with your selection today?</p>
<p style="padding-left: 30px;">Victor: Hi, How are you doing today?</p>
<p style="padding-left: 30px;">Anthony: Great. Just trying to buy Adobe Fireworks</p>
<p style="padding-left: 30px;">Anthony: I&#8217;m based in the United Kingdom</p>
<p style="padding-left: 30px;">Victor: That&#8217;s good to know.</p>
<p style="padding-left: 30px;">Anthony: There&#8217;s no option for that in the &#8220;country&#8221; drop down</p>
<p style="padding-left: 30px;">Victor: I&#8217;ll help you with that.</p>
<p style="padding-left: 30px;">Victor: What do you think the most convenient way of getting the software, downloading or getting CD shipped to you?</p>
<p style="padding-left: 30px;">Anthony: downloading</p>
<p style="padding-left: 30px;">Victor: Alright.</p>
<p style="padding-left: 30px;">Anthony: although if it can be shipped quickly that would be OK</p>
<p style="padding-left: 30px;">Victor: Let me provide you the direct link to place the order. Okay.</p>
<p style="padding-left: 30px;">Anthony: ok</p>
<p style="padding-left: 30px;">Victor: Click here to buy Adobe Fireworks CS5</p>
<p style="padding-left: 30px;">Victor: Please let me know, if you get any error in the order process.</p>
<p style="padding-left: 30px;">Anthony: That&#8217;s £100 more expensive!</p>
<p style="padding-left: 30px;">Anthony: it&#8217;s $299 on the other page</p>
<p style="padding-left: 30px;">Anthony: = £186</p>
<p style="padding-left: 30px;">Victor: In Adobe UK store, Adobe Fireworks CS5 is priced at £285.60.</p>
<p style="padding-left: 30px;">Anthony: how do you explain the price difference?</p>
<p style="padding-left: 30px;">Anthony: even if you add VAT it&#8217;s still £50 more</p>
<p style="padding-left: 30px;">Anthony: i&#8217;m downloading it</p>
<p style="padding-left: 30px;">Anthony: from the same domain</p>
<p style="padding-left: 30px;">Victor: We understand your concern. We want to make sure that we are giving our Customers the best products and at the right price.</p>
<p style="padding-left: 30px;">Victor: Just so you know, there are many factors that decide pricing like &#8216;the cost of doing business in each country&#8217; and the &#8216;difference in the perceived value of the product&#8217;.</p>
<p style="padding-left: 30px;">Victor: However, we&#8217;re sure that the Adobe products add value by helping you get the desired output at ease, efficiency and speed.</p>
<p style="padding-left: 30px;">Anthony: for me the right price is not £285</p>
<p style="padding-left: 30px;">Victor: I understand price is your concern.</p>
<p style="padding-left: 30px;">Anthony: $299 plus VAT sounds like the right price to me</p>
<p style="padding-left: 30px;">Anthony: £224</p>
<p style="padding-left: 30px;">Victor: just to make sure, do you own US credit card with the US billing address?</p>
<p style="padding-left: 30px;">Anthony: no. i&#8217;m based in the UK</p>
<p style="padding-left: 30px;">Anthony: i have a UK address and credit card</p>
<p style="padding-left: 30px;">Victor: In that case you need to buy the software from UK store online.</p>
<p style="padding-left: 30px;">Anthony: I thinking I don&#8217;t need it that much</p>
<p style="padding-left: 30px;">Anthony: thanks for your help</p>
<p style="padding-left: 30px;">Victor: You&#8217;re Welcome.</p>
<p style="padding-left: 30px;">Anthony: I appreciate your time but I feel like I&#8217;m being ripped of</p>
<p style="padding-left: 30px;">Anthony: off</p>
<p style="padding-left: 30px;">Anthony: so won&#8217;t be purchasing the product</p>
<p style="padding-left: 30px;">Victor: Do you&#8217;ve any further questions for me?</p>
<p style="padding-left: 30px;">Anthony: no thank you victor</p>
<p style="padding-left: 30px;">Victor: It was nice chatting with you today.  :)</p>
<p style="padding-left: 30px;">Victor: Thank you for visiting Adobe.com. Have a great day!</p>
<p style="padding-left: 30px;"><strong>Thank you for chatting with us today.</strong></p>
]]></content:encoded>
			<wfw:commentRss>http://www.scarba05.co.uk/blog/2011/11/adobe-fireworks-60-more-expensive-to-download-from-the-uk-than-the-u-s-and-canada/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Using resource registries to merge css and javascript with plone.app.theming (diazo)</title>
		<link>http://www.scarba05.co.uk/blog/2011/11/using-resource-registries-to-merge-css-and-javascript-with-plone-app-theming-diazo/</link>
		<comments>http://www.scarba05.co.uk/blog/2011/11/using-resource-registries-to-merge-css-and-javascript-with-plone-app-theming-diazo/#comments</comments>
		<pubDate>Mon, 07 Nov 2011 10:36:07 +0000</pubDate>
		<dc:creator>Anthony</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.scarba05.co.uk/blog/?p=188</guid>
		<description><![CDATA[One great feature of Plone is the resource registries which speed up the performance of your pages by merging, compressing and improving caching of your CSS and JavaScript resources. plone.app.theming offers many advantages over the traditional way to theme a Plone site but doesn&#8217;t yet support integration with the resource registries. There are plans to [...]]]></description>
			<content:encoded><![CDATA[<p>One great feature of Plone is the resource registries which speed up the performance of your pages by merging, compressing and improving caching of your CSS and JavaScript resources. plone.app.theming offers many advantages over the traditional way to theme a Plone site but doesn&#8217;t yet support integration with the resource registries.</p>
<p>There are plans to add support from Plone 4.3 onwards but here&#8217;s an interim solution I came up with so that I could merge the CSS and JavaScript of my theme right now.  The approach I took is to register my theme&#8217;s CSS and JavaScript in the  registry with conditional logic based on attributes of the request, use one of the existing custom views for an object to set that  attribute on the request and then call templates within ﻿Products.ResourceRegistries.</p>
<h2>Background to the site</h2>
<p>The site I&#8217;m theming has two URLs: one for anonymous, public access; one for the editors.  The editors get the standard Plone sunburst theme with a preview pane whilst the public URL doesn&#8217;t include any CSS or JavaScript and little HTML from the default Plone UI.</p>
<p>The public view is built up of a number of custom views for an object in Plone all pulled together using rules.xml.</p>
<h2>Create the custom view</h2>
<p>Register a new view in configure.zcml</p>
<pre><code>    &lt;browser:page
        for="*"
        name="standard-page-elements"
        template="standard_page_elements.pt"
        permission="zope2.View"
        /&gt;
</code></pre>
<p>Create the custom view class</p>
<pre><code>from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
from Products.ResourceRegistries import browser
from os.path import dirname
from sys import modules

class StandardPageElementsView(BaseThemeView):
    styles_viewlet = ViewPageTemplateFile('styles.pt',
                                  _prefix = dirname(modules['Products.ResourceRegistries.browser'].__file__))
    scripts_viewlet = ViewPageTemplateFile('scripts.pt',
                                  _prefix = dirname(modules['Products.ResourceRegistries.browser'].__file__))
    def mark_request(self):
        self.request.other['plone.app.theming.name'] = 'my.theme'

    def styles(self):
        self.mark_request()
        return self.styles_viewlet(self)

    def scripts(self):
        self.mark_request()
        return self.scripts_viewlet(self)
</code></pre>
<p>Next create the template for the view</p>
<pre><code>&lt;html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:tal="http://xml.zope.org/namespaces/tal"
&lt;head&gt;
    &lt;tal:styles tal:replace="structure view/styles" /&gt;
    &lt;tal:styles tal:replace="structure view/scripts" /&gt;
&lt;/head&gt;
&lt;body&gt;&lt;/body&gt;
&lt;/html&gt;
</code></pre>
<h2>Register the theme&#8217;s resources</h2>
<p>In cssregistry.xml</p>
<pre><code>&lt;stylesheet title="" applyPrefix="True" authenticated="False"
    cacheable="True" compression="safe" conditionalcomment="" cookable="True"
    enabled="on"
    expression="python:portal.REQUEST.other.has_key('plone.app.theming.name')"
    id="++theme++my.them/css/main.css" media="screen" rel="stylesheet"
    rendering="link"/&gt;
&lt;stylesheet title="" applyPrefix="True" authenticated="False"
    cacheable="True" compression="safe" conditionalcomment="" cookable="True"
    enabled="on"
    expression="python:portal.REQUEST.other.has_key('plone.app.theming.name')"
    id="++theme++my.theme/css/other.css" media="screen" rel="stylesheet"
    rendering="link"
    insert-after="++theme++my.theme/css/main.css"/&gt;
</code></pre>
<p>And do something similar for your scripts in jsregistry.xml</p>
<h2>Switch off default Plone CSS and JavaScript</h2>
<p>This is a complete pain (roll on Plone 4.3!).  You need to disable each resource by hand.  I wrote a test for this:</p>
<pre><code>
    def test_css_registry(self):
        css_registry = getToolByName(self.portal, 'portal_css')

        theme_css_ids = ('++theme++my.theme/css/main.css',
                         '++theme++my.theme/css/other.css')

        for css in (css for css in css_registry.getResourcesDict().values() if css.getId() not in theme_css_ids):
            self.assertTrue(css.getExpression().startswith(
                               "python:(not portal.REQUEST.other.has_key('plone.app.theming.name'))"),
                            '%s - %s' % (css.getId(), css.getExpression()))
</code></pre>
<p>And then in cssregistry.xml you need a line for each Plone css file like the following:</p>
<pre><code>&lt;stylesheet expression="python:(not portal.REQUEST.other.has_key('plone.app.theming.name'))" id="member.css"/&gt;
</code></pre>
<p>And then do something similar for jsregistery.xml</p>
<h2>Include via rules.xml</h2>
<p>You need to block stylesheets (including ones in conditional comments) and scripts from the main view and then pull in ones from your custom view:</p>
<pre><code>    &lt;drop theme="/html/head/link[@rel = 'stylesheet']" /&gt;
    &lt;drop theme="/html/head/comment()" /&gt;
    &lt;drop theme="/html/head/script" /&gt;
    &lt;append theme="/html/head" content="/html/head/*" href="@@standard-page-elements" /&gt;
</code></pre>
<h2>Different resources for different pages</h2>
<p>I have the requirement to serve different CSS and scripts for different pages.  I&#8217;ve extended the approach above to register different &#8220;standard-page-elements&#8221; view classes for different objects which set additional attributes on the request.</p>
<h2>Roll on Plone 4.3</h2>
<p>Work is in progress for Products.ResourceRegistries to look up resources based on an adapter and plone.app.theming to register adapters that provide such resources from link and script tags in the html head element of the theme.  If this can be achieved it would obviously be a big win although it sounds tricky for some aspects of existing resource registry functionality like conditional css for IE and specifying which scripts can be compressed safely.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.scarba05.co.uk/blog/2011/11/using-resource-registries-to-merge-css-and-javascript-with-plone-app-theming-diazo/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Copy portlets assigned to one item to another programatically in Plone</title>
		<link>http://www.scarba05.co.uk/blog/2010/12/copy-portlets-assigned-to-one-item-to-another-programatically-in-plone/</link>
		<comments>http://www.scarba05.co.uk/blog/2010/12/copy-portlets-assigned-to-one-item-to-another-programatically-in-plone/#comments</comments>
		<pubDate>Mon, 06 Dec 2010 20:48:48 +0000</pubDate>
		<dc:creator>Anthony</dc:creator>
				<category><![CDATA[Plone]]></category>

		<guid isPermaLink="false">http://www.scarba05.co.uk/blog/?p=163</guid>
		<description><![CDATA[The plone sub-site product Lineage migration script from version 0.1 to 0.6 involves migrating objects that use its obsolete Child Folder custom content type to standard Plone folders marked as child folders using p4a.subtyper.  I've been trying to enhance the migration script so that any portlets attached to a Child Folder items are copied over to the new Folder item as well.  I didn't find any examples of this anywhere so I'm posting here in case anyone should needs to do something similar.]]></description>
			<content:encoded><![CDATA[<p>The <a href="http://plone.org/products/collective-lineage">plone sub-site product Lineage</a> migration script from version 0.1 to 0.6 involves migrating objects that use its obsolete Child Folder custom content type to standard Plone folders marked as child folders using <a href="http://pypi.python.org/pypi/p4a.subtyper">p4a.subtyper</a>.  I&#8217;ve been trying to enhance the migration script so that any portlets attached to a Child Folder items are copied over to the new Folder item as well.  I didn&#8217;t find any examples of this anywhere so I&#8217;m posting here in case anyone should needs to do something similar.</p>
<p>Here&#8217;s the code I used.  A few things that I learnt along the way:</p>
<ul>
<li>contextual portlets are managed by Zope local utilities</li>
<li>you have a <code>IPortletManager</code> local utility for each portlet area defined.  Plone comes with two of these &#8216;plone.leftcolumn&#8217; and &#8216;plone.rightcolumn&#8217; but you can add more</li>
<li>An <code>IPortletAssignmentMapping</code> adaptor adapts your context and its portlet manager to provide storage for your portlet assignments for that context</li>
<li>A <code>ILocalPortletAssignmentManager</code> adaptor adapts your context and its portlet manager to provide storage for your blocking settings for that context</li>
</ul>
<pre><code>from logging import getLogger
from plone.portlets.interfaces import ILocalPortletAssignable
from plone.portlets.interfaces import ILocalPortletAssignmentManager
from plone.portlets.interfaces import IPortletAssignmentMapping
from plone.portlets.interfaces import IPortletManager
from plone.portlets.constants import CONTEXT_CATEGORY, GROUP_CATEGORY, CONTENT_TYPE_CATEGORY

from zope.interface import alsoProvides
from zope.component import getMultiAdapter
from zope.component import getUtility
from zope.component import getUtilitiesFor
from zope.component import queryUtility
from zope.component import provideUtility

logger = getLogger('scarba05.utils')

def copy_portlet_assignments_and_settings(src, target):
    """Copy portlet assignments from src to target"""
    if not ILocalPortletAssignable.providedBy(src):
        alsoProvides(src, ILocalPortletAssignable)

    for manager_name, src_manager in getUtilitiesFor(IPortletManager, context=src):
        src_manager_assignments = getMultiAdapter((src, src_manager), IPortletAssignmentMapping)
        target_manager = queryUtility(IPortletManager, name=manager_name, context=target)
        if target_manager is None:
            logger.warning('New folder %s does not have portlet manager %s' %
                           (target.getId(), target_manager))
        else:
            target_manager_assignments = getMultiAdapter((target, target_manager),
                                                IPortletAssignmentMapping)
            for id, assignment in src_manager_assignments.items():
                target_manager_assignments[id] = assignment
            src_assignment_manager = getMultiAdapter((src, src_manager),
                                                 ILocalPortletAssignmentManager)
            target_assignment_manager = getMultiAdapter((target, target_manager),
                                                 ILocalPortletAssignmentManager)
            for category in (CONTEXT_CATEGORY, GROUP_CATEGORY, CONTENT_TYPE_CATEGORY):
                target_assignment_manager.setBlacklistStatus(category,
                                      src_assignment_manager.getBlacklistStatus(category))
</code></pre>
<p>I ended up tweaking this code a little for the actual migration step as in Lineage 0.1 Child Folders didn&#8217;t inherit their parents portlets, no matter what the parent portlet block settings were.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.scarba05.co.uk/blog/2010/12/copy-portlets-assigned-to-one-item-to-another-programatically-in-plone/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Including a file extension for the Plone News item image</title>
		<link>http://www.scarba05.co.uk/blog/2010/11/including-a-file-extension-for-the-plone-news-item-image/</link>
		<comments>http://www.scarba05.co.uk/blog/2010/11/including-a-file-extension-for-the-plone-news-item-image/#comments</comments>
		<pubDate>Thu, 11 Nov 2010 14:42:13 +0000</pubDate>
		<dc:creator>Anthony</dc:creator>
				<category><![CDATA[Plone]]></category>

		<guid isPermaLink="false">http://www.scarba05.co.uk/blog/?p=158</guid>
		<description><![CDATA[We&#8217;ve configured our Plone site so that our news section appears in Google news by regularly submitting a news sitemap to Google. Unfortunately news items that appear in Google don&#8217;t have a picture associated with them. Having looked at the Google news guidelines for images it seems this is almost certainly because the image url [...]]]></description>
			<content:encoded><![CDATA[<p>We&#8217;ve configured our Plone site so that our news section appears in Google news by regularly submitting a news sitemap to Google.  Unfortunately news items that appear in Google don&#8217;t have a picture associated with them.  Having looked at the <a href="http://www.google.com/support/news_pub/bin/answer.py?hl=en&amp;answer=13369">Google news guidelines for images</a> it seems this is almost certainly because the image url for the image added to the Plone News item doesn&#8217;t include a file extension.</p>
<p>Following a suggestion on the <a href="http://plone.293351.n2.nabble.com/Google-news-doesn-t-include-News-item-image-best-way-to-add-a-file-extension-to-the-url-tp5638329p5638329.html">Plone forum</a> To get round this we&#8217;re going to try the following:</p>
<ul>
<li>Create a BrowserView with a custom traverser that renders the image</li>
<li>Override the news item template to use the url expected by the new browser view</li>
</ul>
<p>I&#8217;ve managed to get this working quite neatly:</p>
<pre><code>from mimetypes import guess_type

from plone.app.layout.viewlets.common import BrowserView

from zope.publisher.interfaces import NotFound

class ImageView(BrowserView):
"""A view of a new item's image that supports file extensions"""

    def __getitem__(self, partid):
        (type, encoding) = guess_type(partid)
        image_type = self.context.getField('image').getContentType(self.context)

        if not type == image_type:
            raise NotFound(self.context, partid, self.request)

        return self.context.__bobo_traverse__(self.request, partid[:partid.find('.')])</code></pre>
<p>This simple bit of code will work for all image scales and validates that the extension used matches the content type of the image.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.scarba05.co.uk/blog/2010/11/including-a-file-extension-for-the-plone-news-item-image/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>More on integration testing of Spring’s MVC annotation mapppings for controllers</title>
		<link>http://www.scarba05.co.uk/blog/2010/07/more-on-integration-testing-of-spring%e2%80%99s-mvc-annotation-mapppings-for-controllers/</link>
		<comments>http://www.scarba05.co.uk/blog/2010/07/more-on-integration-testing-of-spring%e2%80%99s-mvc-annotation-mapppings-for-controllers/#comments</comments>
		<pubDate>Wed, 28 Jul 2010 20:28:04 +0000</pubDate>
		<dc:creator>Anthony</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Spring Framework]]></category>

		<guid isPermaLink="false">http://www.scarba05.co.uk/blog/?p=143</guid>
		<description><![CDATA[A while back I posted some thoughts on how to integration test Spring’s MVC annotation mapppings for controllers.  Since then I&#8217;ve developed my strategy a little further after find a few gaps in my original tests. Integration testing interceptors and @PathVariable The most noticeable problem with my original approach is that it doesn&#8217;t test any [...]]]></description>
			<content:encoded><![CDATA[<p>A while back I posted some thoughts on <a href="http://www.scarba05.co.uk/blog/2010/03/integration-testing-of-springs-mvc-annotation-mapppings-for-controllers/">how to integration test Spring’s MVC annotation mapppings for controllers</a>.  Since then I&#8217;ve developed my strategy a little further after find a few gaps in my original tests.</p>
<h2>Integration testing interceptors and <code>@PathVariable</code></h2>
<p>The most noticeable problem with my original approach is that it doesn&#8217;t test any interceptors that are configured and this is something you probably want to include in your integration tests.  One unexpected (for me at least) side effect of this is that methods that include <code>@PathVariable</code> annotations on their parameters don&#8217;t work either.  You get the following exception:</p>
<p><samp>org.springframework.web.bind.annotation.support.HandlerMethodInvocationException: Failed to invoke handler method [public org.springframework.web.servlet.ModelAndView test.MyClass.myMethod(test.SomeType)]; nested exception is java.lang.IllegalStateException: Could not find @PathVariable [parameterName] in @RequestMapping</samp></p>
<p>This is because an interceptor is used by Spring to extract path variables from the request, before it hits the controller and processes the corresponding annotated parameters.</p>
<h2>Use common handle method in integration tests</h2>
<p>Using the same example class before:</p>
<pre><code>@Controller
@RequestMapping("/simple-form")
public class MyController {
    private final static String FORM_VIEW = null;

    @InitBinder
    public void initBinder(WebDataBinder binder) {
        binder.registerCustomEditor(String.class, new StringTrimmerEditor(false));
    }

    @RequestMapping(method = RequestMethod.GET)
    public MyForm newForm() {
        return new MyForm();
    }

    @RequestMapping(method = RequestMethod.POST)
    public String processFormSubmission(@Valid MyForm myForm,
            BindingResult result) {
        if (result.hasErrors()) {
            return FORM_VIEW;
        }
        // process the form
        return "success-view";
    }
}
</code></pre>
<p>Here&#8217;s my updated implementation of an integration test.  In it I define a handle method that is called by each test after it has configured the <var>request</var> to mimic that sent by the browser.  This handle method includes logic to execute each of the interceptors configured for that request first, before passing control to the controller.  It also makes no assumption about what class the controller is.</p>
<pre><code>@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"file:web/WEB-INF/application-context.xml",
    "file:web/WEB-INF/dispatcher-servlet.xml"})
public class MyControllerIntegrationTest {

    @Inject
    private ApplicationContext applicationContext;

    private MockHttpServletRequest request;
    private MockHttpServletResponse response;
    private HandlerAdapter handlerAdapter;

    @Before
    public void setUp() throws Exception {
        this.request = new MockHttpServletRequest();
        this.response = new MockHttpServletResponse();

        this.handlerAdapter = applicationContext.getBean(HandlerAdapter.class);
    }

    ModelAndView handle(HttpServletRequest request, HttpServletResponse response)
            throws Exception {
        final HandlerMapping handlerMapping = applicationContext.getBean(HandlerMapping.class);
        final HandlerExecutionChain handler = handlerMapping.getHandler(request);
        assertNotNull("No handler found for request, check you request mapping", handler);

        final Object controller = handler.getHandler();
        // if you want to override any injected attributes do it here

        final HandlerInterceptor[] interceptors =
            handlerMapping.getHandler(request).getInterceptors();
        for (HandlerInterceptor interceptor : interceptors) {
            final boolean carryOn = interceptor.preHandle(request, response, controller);
            if (!carryOn) {
                return null;
            }
        }

        final ModelAndView mav = handlerAdapter.handle(request, response, controller);
        return mav;
    }

    @Test
    public void testNewForm() throws Exception {
        request.setMethod("GET");
        request.setRequestURI("/simple-form");

        final ModelAndView mav = handle(request, response);
        // make assertions on the ModelAndView here
    }

    @Test
    public void testProcessFormSubmission() throws Exception {
        request.setMethod("POST");
        request.setRequestURI("/simple-form");
        // set some request parameters for binding

        final ModelAndView mav = handle(request, response);
        // make assertions on the ModelAndView here plus any side effects
    }
</code></pre>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">
<h1><a title="Permanent Link to Integration testing of Spring’s MVC annotation mapppings for controllers" rel="bookmark" href="../2010/03/integration-testing-of-springs-mvc-annotation-mapppings-for-controllers/">Integration testing of Spring’s MVC annotation mapppings for controllers</a></h1>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.scarba05.co.uk/blog/2010/07/more-on-integration-testing-of-spring%e2%80%99s-mvc-annotation-mapppings-for-controllers/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Wish list #2: Specify which JSR 303 group to validate with method level annotation</title>
		<link>http://www.scarba05.co.uk/blog/2010/04/specify-which-jsr-303-group-to-validate-with-method-level-annotation/</link>
		<comments>http://www.scarba05.co.uk/blog/2010/04/specify-which-jsr-303-group-to-validate-with-method-level-annotation/#comments</comments>
		<pubDate>Wed, 14 Apr 2010 10:29:55 +0000</pubDate>
		<dc:creator>Anthony</dc:creator>
				<category><![CDATA[Spring Framework]]></category>
		<category><![CDATA[Wish list]]></category>

		<guid isPermaLink="false">http://www.scarba05.co.uk/blog/?p=123</guid>
		<description><![CDATA[javax.validation integration with Spring 3.0 MVC is cool Spring 3.0 includes some great features and one of my favourites is its integration with the JSR 303 bean validation API.  It uses the method-level validation proposal from the specification.  Note the word proposal: Method-level @Valid annotations are mentioned in an appendix rather than in the official [...]]]></description>
			<content:encoded><![CDATA[<h2>javax.validation integration with Spring 3.0 MVC is cool</h2>
<p>Spring 3.0 includes some great features and one of my favourites is its integration with the <abbr title="Java Specification Request">JSR</abbr> 303 bean validation API.  It uses the method-level validation proposal from the specification.  Note the word proposal: Method-level <code>@Valid</code> annotations are mentioned in an appendix rather than in the official part of the specification.  Basically you annotate the form bean parameter with <code>@Valid</code> and include a <code>BindingResult</code> paramater on your handler method and Spring validates the bean after binding, populating the <code>BindingResult</code> instance with any errors that occur.</p>
<pre><code>    @RequestMapping(method = RequestMethod.POST)
    public String saveForm(@Valid MyForm myForm, BindingResult result) {
        if (result.hasErrors()) {
            // usually return the user back to the form
        }
        // process the form
    }
</code></pre>
<p>You obviously also need to annotate you form bean class with JSR 303 annotations.</p>
<h2>What about multi page (wizard style) forms?</h2>
<p>All this works great with one page forms but what happens when your form spans more than one page?  Validation and other Spring MVC 3.0 features work great for single page forms but there&#8217;s not much out of the box support wizard style forms yet.  These types of forms are very common for checkout style processes and forms where more complex interaction is required, for example, where a user is asked different sets of questions based on their earlier answers.</p>
<p>I&#8217;ve been working on an online donation, multi page, wizard and wanted to use the new Spring 3.0 MVC style rather than the old Spring 2.0 <code>AbstractWizardFormController</code>.  I&#8217;ll probably post more about my solution later but it involved using a <abbr title="Hyper-text transfer protocol">HTTP</abbr> request parameter to specify the page, a handler method per page in my controller and the params parameter of the <code>@RequestMapping</code> annotation to help Spring select the correct method.</p>
<pre><code>    @RequestMapping(method = RequestMethod.POST, params = "page=1")
    public String handlePage1(MyForm myForm, BindingResult result) {
        // what about validation?
    }
</code></pre>
<h2>Spring 3.0 integration with JSR 303 validation doesn&#8217;t work with multi page forms</h2>
<p>My requirements (like most multi page forms) is to validate the data submitted by the user on the submission of the page where they entered it.  If I annotate my form bean method parameter with <code>@Valid</code> then it validates the whole bean and there&#8217;s currently no way round this.  This won&#8217;t work: mandatory fields on page 2 of the form won&#8217;t be filled in when the user submits page 1.</p>
<p>JSR 303 validation does have the concept of groups.  You can specify which groups each validation annotation applies to and map these groups to your various pages:</p>
<pre><code>@GroupSequence({MyForm.class, MyForm.Page1.class, MyForm.Page2.class})
public class MyForm {
    public static interface Page1 {}
    public static interface Page2 {}

    @NotNull(groups = {Page1.class})
    private String page1MandatoryField;

    @NotNull(groups = {Page2.class})
    private String page2MandatoryField;

    ...
}
</code></pre>
<p>For real applications you&#8217;re better naming your groups based on what&#8217;s on the page, rather than its number.</p>
<p>JSR 303 then provides mechanisms for you to validate only a specify group or groups on a bean (great!) but there&#8217;s no way of integrating this with Spring MVC binding step (not great!).</p>
<h1>Extend JSR 303 <code>@Valid</code> annotation to specify which group to validate</h1>
<p>I can work round this pain by manually calling the group validation step in my handler methods.  This is exactly the kind of boiler plate repetitive code Spring is usually so good at doing for you. What I&#8217;d really like is to be able specify which groups I want Spring to validate using an annotation.  The most elegant solution I believe would be to extend the <code>@Valid</code> annotation to include a groups parameter:</p>
<pre><code>    @RequestMapping(method = RequestMethod.POST, params = "page=1")
    public String handlePage1(@Valid<ins title="New groups parameter for annotation (not supported yet!)">(groups = {Page1.class})</ins> MyForm myForm,
            BindingResult result) {
        if (result.hasErrors()) {
            return "page1";
        }
        return "page2";
}
</code></pre>
<p>The @Valid annotation primary purpose is for cascading validation down the object graph.  I believe a groups parameter would also be useful for this purpose but don&#8217;t have a concrete example of this.</p>
<p>Obviously extending the specification and implementation the solution is out of Spring&#8217;s hands so in the interim maybe Spring could provide a @ValidationGroups parameter to do the job for you:</p>
<pre>    @RequestMapping(method = RequestMethod.POST, params = "page=1")
    public String handlePage1(@Valid <ins title="New Spring annotation for specifying validation groups (not supported yet!)">@ValidationGroups(Page1.class)</ins> MyForm myForm,
            BindingResult result) {
        if (result.hasErrors()) {
            return "page1";
        }
        return "page2";
}
</pre>
<p>There&#8217;s already a <a href="https://jira.springsource.org/browse/SPR-6373">Spring feature request</a> asking for something along these lines.   Please go and vote for it!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.scarba05.co.uk/blog/2010/04/specify-which-jsr-303-group-to-validate-with-method-level-annotation/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Character encoding issue using @RequestMapping annotation with params parameter on Tomcat</title>
		<link>http://www.scarba05.co.uk/blog/2010/03/requestmapping-annotation-params-parameter-character-encoding-issue/</link>
		<comments>http://www.scarba05.co.uk/blog/2010/03/requestmapping-annotation-params-parameter-character-encoding-issue/#comments</comments>
		<pubDate>Tue, 23 Mar 2010 12:10:25 +0000</pubDate>
		<dc:creator>Anthony</dc:creator>
				<category><![CDATA[Spring Framework]]></category>
		<category><![CDATA[Tomcat]]></category>

		<guid isPermaLink="false">http://www.scarba05.co.uk/blog/?p=109</guid>
		<description><![CDATA[I found a little gotcha today after using the params parameter of Spring 3.0&#8242;s @RequestMapping annotation. The params parameter lets you map requests to methods in your Spring controller based on the value of HTTP parameters. I was implementing a wizard style set of forms today for the first time using Spring 3.0 and decided [...]]]></description>
			<content:encoded><![CDATA[<p>I found a little gotcha today after using the params parameter of Spring 3.0&#8242;s <code>@RequestMapping</code> annotation.  The params parameter lets you map requests to methods in your Spring controller based on the value of <abbr title="Hypertext Transfer Protocol">HTTP</abbr> parameters.  I was implementing a wizard style set of forms today for the first time using Spring 3.0 and decided that this would fit really well.  For example I could write something like:</p>
<pre><code>    @RequestMapping(method = POST, params = "page=1")
    public String handlePage1(@Valid MyForm form, BindingResult result) {
       if (result.hasErrors()) {
           return "page1";
       }
       return "page2";
    }
</code></pre>
<p>We&#8217;re using Tomcat 6 as our servlet container and have previously found that to get it to handle non-ASCII characters correctly you need to set the character encoding on the request.  In Spring 3.0 world we&#8217;ve been doing this in our <code>@InitBinder</code> annotated method.</p>
<pre><code>    @InitBinder
    public void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) {
        request.setCharacterEncoding("UTF-8");
        // initialize the binder
    }
</code></pre>
<p>For some reason this wasn&#8217;t working in my new form: special characters submitted in the form weren&#8217;t being encoded properly.  This had me baffled for a while until I realized what the culprit was: my use of the params parameter with the @RequestMapping annotation!  After debugging it became apparent that using it causes HTTP request parameters to be parsed before the <code>initBinder</code> method is called and any further calls to <code>request.getParameter()</code> ignore the character encoding specified (possibly because the result is cached by the Tomcat implementation?).  This means I needed to set the character encoding before the <code>HandlerAdaptor</code> starts working on the <code>@RequestMapping</code> annotated methods.</p>
<h2>Solution: set the character encoding via an interceptor</h2>
<p>I managed to resolve this by creating a Spring interceptor (equivalent of a JEE Filter) to set the character encoding .</p>
<pre><code>package com.example;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

/**
 * Sets the character encoding for the request.  Defaults to UTF-8.
 */
public class SetCharacterEncodingInterceptor extends HandlerInterceptorAdapter {
    private String characterEncoding = "UTF-8";

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
            Object handler) throws Exception {
        request.setCharacterEncoding(this.characterEncoding);
        return true;
    }

    public void setCharacterEncoding(String characterEncoding) {
        this.characterEncoding = characterEncoding;
    }
}</code></pre>
<p>and then configuring Spring to use this interceptor for all my controllers:</p>
<pre><code>    &lt;mvc:interceptors&gt;
        <ins title="Configure the interceptor to work with every controller">&lt;bean class="com.example.SetCharacterEncodingInterceptor"/&gt;</ins>
    &lt;/mvc:interceptors&gt;

</code></pre>
<p>This meant I no longer need to set the encoding in my <code>initBinder</code> methods: removing duplicate code as a bonus:</p>
<pre><code>    @InitBinder
    public void initBinder(<del title="No longer need to pass in the request">HttpServletRequest request, </del>ServletRequestDataBinder binder) {
        <del title="Remove the redundant code">request.setCharacterEncoding("UTF-8");</del>
        // initialize the binder
    }
</code>
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.scarba05.co.uk/blog/2010/03/requestmapping-annotation-params-parameter-character-encoding-issue/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Integration testing of Spring&#8217;s MVC annotation mapppings for controllers</title>
		<link>http://www.scarba05.co.uk/blog/2010/03/integration-testing-of-springs-mvc-annotation-mapppings-for-controllers/</link>
		<comments>http://www.scarba05.co.uk/blog/2010/03/integration-testing-of-springs-mvc-annotation-mapppings-for-controllers/#comments</comments>
		<pubDate>Tue, 16 Mar 2010 20:13:41 +0000</pubDate>
		<dc:creator>Anthony</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Spring Framework]]></category>

		<guid isPermaLink="false">http://www.scarba05.co.uk/blog/?p=90</guid>
		<description><![CDATA[See also my follow up most: More on integration testing of Spring’s MVC annotation mapppings for controllers I really love Spring 3&#8242;s MVC annotation based controllers. I was quite fond of the old style (and now largely deprecated) hierarchy of controllers provided by Spring 2: They removed the need for a lot of boiler plate [...]]]></description>
			<content:encoded><![CDATA[<p><em>See also my follow up most: <a href="http://www.scarba05.co.uk/blog/2010/07/more-on-integration-testing-of-spring%E2%80%99s-mvc-annotation-mapppings-for-controllers/">More on integration testing of Spring’s MVC annotation mapppings for controllers</a></em><br />
I really love Spring 3&#8242;s <abbr title="model - view - controller">MVC</abbr> annotation based controllers.  I was quite fond of the old style (and now largely deprecated) hierarchy of controllers provided by Spring 2:  They removed the need for a lot of boiler plate code especially around parsing, validating and processing form submissions.  However it always felt like you were building your controller implementations on top of a bit of a beast requiring knowledge of a long chain of events which you could hook into.  With the annotation approach in Spring 3 my controllers feel light, less coupled and largely contain logic specific to my application.</p>
<p>As a very simple example.  Say you want a controller that processes a simple form.</p>
<pre><code>@Controller
@RequestMapping("/simple-form")
public class MyController {
    private final static String FORM_VIEW = null;

    @InitBinder
    public void initBinder(WebDataBinder binder) {
        binder.registerCustomEditor(String.class, new StringTrimmerEditor(false));
    }

    @RequestMapping(method = RequestMethod.GET)
    public MyForm newForm() {
        return new MyForm();
    }

    @RequestMapping(method = RequestMethod.POST)
    public String processFormSubmission(@Valid MyForm myForm,
            BindingResult result) {
        if (result.hasErrors()) {
            return FORM_VIEW;
        }
        // process the form
        return "success-view";
    }
}
</code></pre>
<p>This is great because:</p>
<ul>
<li>The controller doesn&#8217;t extend a Spring class</li>
<li>You can call your methods that handle requests whatever you like (i.e. a name which best expresses their intention) with the <code>@RequestMapping</code> annotation reinforcing this view</li>
<li>There is virtually no boiler plate code</li>
<li>It&#8217;s integrated with the JSR 303 validation API</li>
<li>You decide what parameters go in the controller methods and Spring calls the method passing in the appropriate object</li>
</ul>
<h2>Confession: I haven&#8217;t been writing tests for the <code>@RequestMapping</code>, <code>@RequestParam</code>, <code>@PathVariable</code> and other annotations</h2>
<p>Throughout the last two months of using the new features I&#8217;ve have had a nagging feeling that I haven&#8217;t been writing enough JUnit tests.  I&#8217;m very keen on writing tests and we use test-driven-development most of the time.  Unit testing the logic inside the controller methods is no issue.  In fact, that&#8217;s another great thing about Spring 3 controllers: they&#8217;re really easy to unit test.  We also continue to build up our bank of end to end regression tests using <a href="http://seleniumhq.org/">Selenium</a> (excellent tool!).</p>
<p>What is missing are tests that ensure I&#8217;ve used the correct annotation in the correct place.  In the Spring reference manual tests of this nature are called <q cite="http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/testing.html#integration-testing">integration tests</q> and it talks about how you might want to write tests for Hibernate entity annotations and similar.  Looking into this I haven&#8217;t been able to find a satisfactory approach for testing the MVC annotations:  I&#8217;ve read suggestions to test a method is annotated with a particular annotation or to write functional tests with something like HtmlUnit.  What I want is something similar to the recommendation in the Spring documentation for writing database integration tests.</p>
<p>I&#8217;ve also read suggestions that I don&#8217;t need to test the annotations because Spring will have tests that already do that.  To me that argument is specious:  I&#8217;m not testing that the Spring annotations do what they&#8217;re supposed to, I&#8217;m testing that I&#8217;ve used the annotations correctly.</p>
<h2>How to write integration tests for Spring MVC annotations</h2>
<p>Here&#8217;s my approach to writing integration tests for Spring MVC annotations.  Taking the example above my code that I want to test would be for a <abbr title="hypertext transfer protocol">HTTP</abbr> <var>GET</var>:</p>
<ul>
<li>results in a null view</li>
<li>a new command object being placed in the model</li>
</ul>
<p>and a HTTP <var>POST</var>:</p>
<ul>
<li>request parameters are bound to a command object</li>
<li>the parameter values are trimmed</li>
<li>the command object is validated and if not valid the errors are included in a binding result in the model and a null view returned</li>
</ul>
<p>More generally I want to test that:</p>
<ul>
<li>my Spring configuration files correctly configure the appropriate HandlerAdaptor</li>
</ul>
<pre><code>import static org.springframework.test.web.ModelAndViewAssert.*;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"file:web/WEB-INF/application-context.xml",
    "file:web/WEB-INF/dispatcher-servlet.xml"})
public class MyControllerIntegrationTest {

    @Inject
    private ApplicationContext applicationContext;

    private MockHttpServletRequest request;
    private MockHttpServletResponse response;
    private HandlerAdapter handlerAdapter;
    private MyController controller;

    @Before
    public void setUp() {
       request = new MockHttpServletRequest();
       response = new MockHttpServletResponse();
       handlerAdapter = applicationContext.getBean(HandlerAdapter.class);
       // I could get the controller from the context here
       controller = new MyController();
    }

    @Test
    public void testGet() throws Exception {
       request.setMethod("GET");
       final ModelAndView mav = handlerAdapter.handle(request, response, controller);
       assertViewName(mav, null);
       assertAndReturnModelAttributeOfType(mav, "myForm", MyForm.class);
    }

    @Test
    public void testPost() throws Exception {
       request.setMethod("POST");
       request.addParameter("firstName", "  Anthony  ");
       final ModelAndView mav = handlerAdapter.handle(request, response, controller);
       final MyForm myForm = assertAndReturnModelAttributeOfType(mav, "myForm", MyForm.class);
       assertEquals("Anthony", myForm.getFirstName());

       /* if myForm is not valid */
       assertViewName(mav, null);
       final BindingResult errors = assertAndReturnModelAttributeOfType(mav,
               "org.springframework.validation.BindingResult.myForm",
               BindingResult.class);
       assertTrue(errors.hasErrors());
    }
}</code></pre>
<p>It should be fairly easy to extend this to more complex examples testing <code>@RequestParam</code>, <code>@RequestMethod</code>, <code>@PathVariable</code>, <code>@RequestHeader</code>,  <code>@RequestBody.</code></p>
<h2>What&#8217;s next</h2>
<p>You might notice that I&#8217;m not testing the <code>@RequestMapping("/simple-form")</code> class level annotation in this test.  I&#8217;ve not figured out what the best way to do this is just yet.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.scarba05.co.uk/blog/2010/03/integration-testing-of-springs-mvc-annotation-mapppings-for-controllers/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Configure Tomat 6 to use the Apache Portable Runtime (APR) libraries</title>
		<link>http://www.scarba05.co.uk/blog/2010/03/configure-tomat-6-to-use-the-apache-portable-runtime-apr-libraries/</link>
		<comments>http://www.scarba05.co.uk/blog/2010/03/configure-tomat-6-to-use-the-apache-portable-runtime-apr-libraries/#comments</comments>
		<pubDate>Thu, 11 Mar 2010 14:11:33 +0000</pubDate>
		<dc:creator>Anthony</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Tomcat]]></category>

		<guid isPermaLink="false">http://www.scarba05.co.uk/blog/?p=75</guid>
		<description><![CDATA[I&#8217;ve had a bit of bother trying to configure our Tomcat server to use the APR libraries today.  I&#8217;ve managed to get it working eventually but thought it worth posting something about it as the documentation is a little scarce.  First off I&#8217;ll document what I should have done from the start and then I&#8217;ll [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve had a bit of bother trying to configure our Tomcat server to use the <abbr title="Apache Portable Runtime">APR</abbr> libraries today.  I&#8217;ve managed to get it working eventually but thought it worth posting something about it as the <a title="Tomcat 6.0 APR documentation" href="http://tomcat.apache.org/tomcat-6.0-doc/apr.html">documentation</a> is a little scarce.  First off I&#8217;ll document what I should have done from the start and then I&#8217;ll list the errors I encountered figuring all this out.</p>
<h2>How do I know if Tomcat is using APR or not?</h2>
<p>If Tomcat is not using APR then you&#8217;ll see the following log line (or something similar) when you start it.</p>
<pre><samp>INFO: The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: /home/tomcat6live/java.home/jre/lib/i386/server:/home/tomcat6live/java.home/jre/lib/i386:/usr/java/packages/lib/i386:/lib:/usr/lib</samp></pre>
<p>If it is using APR then you&#8217;ll see something like</p>
<pre><samp>INFO: Loaded APR based Apache Tomcat Native library 1.1.19.</samp></pre>
<p>If you don&#8217;t see either or these lines then either you&#8217;ve configured logging above INFO on <code>org.apache.catalina.core.AprLifecycleListener</code> or you haven&#8217;t included the APR listener in your server.xml (see below).</p>
<h2>Prerequisites</h2>
<p>You need the APR and openSSL libraries installed on your server. We&#8217;d already installed them on our server so I&#8217;m not going to blog about how to install them here.</p>
<h2>Install the Tomcat APR native libraries</h2>
<p>As root:</p>
<pre><kbd>cd /usr/local/apache-tomcat-6.0.24/bin
tar xfz tomcat-native.tar.gz
cd tomcat-native-1.1.19-src/jni/native
./configure --with-apr=/usr/local/apr --with-ssl=/usr/local --prefix=/usr/local/apache-tomcat-6.0.24  --with-java-home=/usr/java/jdk1.6.0_17
make
make install</kbd></pre>
<p>Where you should adjust the ./configure parameters so that they match you APR, SSL, Tomcat and Java installations on your server.</p>
<h2>Configure Tomcat to use the APR native libraries</h2>
<p>The LD_LIBRARY path variable needs to include the Tomcat lib directory.  I have a setenv file that is referenced by our init.d start-up script so I simply added the following lines to that.</p>
<pre><code>LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$CATALINA_HOME/lib
export LD_LIBRARY_PATH</code></pre>
<p>Your start-up script needs to do something similar.</p>
<p>Now all you need to do is ensure the APR listener is configured in server.xml.  We have the following (which you&#8217;ll need to adjust if you&#8217;re using SSL).</p>
<pre><code>&lt;Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="off" /&gt;</code></pre>
<p>All done!</p>
<h1>Problems getting Tomcat to use the APR native libraries</h1>
<p>Like I mentioned earlier I encounted a number of issues along the way.</p>
<h2>Error initializing endpoint / Invalid Server SSL Protocol</h2>
<p>Tomcat started but with lots of errors.  This being the first:</p>
<pre><samp>SEVERE: Error initializing endpoint
java.lang.Exception: Invalid Server SSL Protocol
        at org.apache.tomcat.jni.SSLContext.make(Native Method)
        at org.apache.tomcat.util.net.AprEndpoint.init(AprEndpoint.java:716)
        at org.apache.coyote.http11.Http11AprProtocol.init(Http11AprProtocol.java:107)
        at org.apache.catalina.connector.Connector.initialize(Connector.java:1007)
        at org.apache.catalina.core.StandardService.initialize(StandardService.java:677)
        at org.apache.catalina.core.StandardServer.initialize(StandardServer.java:795)
        at org.apache.catalina.startup.Catalina.load(Catalina.java:540)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.apache.catalina.startup.Bootstrap.load(Bootstrap.java:261)
        at org.apache.catalina.startup.Bootstrap.init(Bootstrap.java:276)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.apache.commons.daemon.support.DaemonLoader.load(DaemonLoader.java:160)
</samp></pre>
<p>This was because I had <code>SSLEngine="off"</code> in my APR listener configuration</p>
<pre><code>&lt;Listener className="org.apache.catalina.core.AprLifecycleListener"  SSLEngine="off" /&gt;</code></pre>
<p>But had a http connector configured to use SSL</p>
<pre><code>&lt;Connector protocol="HTTP/1.1" ... SSLEnabled="true" ... /&gt;</code></pre>
<p>Fix seemed simple &#8211; switch the ssl engine on!</p>
<pre><code>&lt;Listener className="org.apache.catalina.core.AprLifecycleListener"   SSLEngine="<del>off</del><ins>on</ins>" /&gt;</code></pre>
<h2>symbol lookup error / undefined symbol: SSL_CTX_set_info_callback</h2>
<p>Now Tomcat wouldn&#8217;t start at all!  This was the error:</p>
<pre><samp>jsvc.exec: symbol lookup error: /usr/local/apache-tomcat-6.0.24/lib/libtcnative-1.so.0.1.19: undefined symbol: SSL_CTX_set_info_callback
</samp></pre>
<p>This was due to the fact I hadn&#8217;t used the correct value for the <code>--with-ssl</code> option when I ran <kbd>./configure</kbd> (see above).  I&#8217;d used <var>/usr/share/ssl</var> when I should have used <var>/usr/local</var>.  To fix I reran <kbd>./configure</kbd> with the correct values.  You can check the output to make sure it finds a compatible version of ssl.  You then need to remake the libraries.</p>
<pre><kbd>make clean
make
make install</kbd></pre>
<h2>Error initializing endpoint / No Certificate file specified or invalid file format</h2>
<p>Now Tomcat starts but with a number of SEVERE errors.  In particular:</p>
<pre><samp>SEVERE: Error initializing endpoint
java.lang.Exception: No Certificate file specified or invalid file format
        at org.apache.tomcat.jni.SSLContext.setCertificate(Native Method)
</samp></pre>
<p>This was caused by a misconfiguration of our http connector that was using SSL.  It turns out that: <q cite="http://tomcat.apache.org/tomcat-6.0-doc/ssl-howto.html">The APR connector uses different attributes for SSL keys and certificates.</q> How <em>annoying</em>!  We only need SSL on our local development environments as Apache looks after the SSL handshake on our production servers so I simply switched off the SSL Engine on our APR listener and disabled SSL on the http connector in server.xml.  If you need SSL with APR then you can find instructions in the <a href="http://tomcat.apache.org/tomcat-6.0-doc/ssl-howto.html">Tomcat 6.0 documentation page on SSL</a>.</p>
<pre><code>&lt;Listener className="org.apache.catalina.core.AprLifecycleListener"   SSLEngine="<del>on</del><ins>off</ins>" /&gt;</code>
…
&lt;Connector protocol="HTTP/1.1" ... SSLEnabled="<del>true</del><ins>false</ins>" ... /&gt;</pre>
<p>At last everything works!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.scarba05.co.uk/blog/2010/03/configure-tomat-6-to-use-the-apache-portable-runtime-apr-libraries/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

